You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue2集成Sendbird实现图片文件上传至聊天日志的问题求助

Sendbird Vue2 图片上传至聊天日志问题排查与修复

问题描述

使用Sendbird构建聊天组件,适配Vue2.js后,图片上传功能异常:能正常选择文件(console.log可查看文件信息),但无法将文件上传到聊天日志中。

相关代码

SendbirdAction.js

sendFileMessage(file) {
  const fileMessageParams = this.sb.FileMessageParams();
  fileMessageParams.file = file;

  return new Promise((resolve, reject) => { 
    this.channel.sendFileMessage(fileMessageParams, (file, error) => {
      error? reject(error) : resolve(file)
    })
  })
}

MessageInput.vue

<template>
  <div>
    <!-- File Upload -->
    <!-- Photo -->
    <!-- Emoji -->
    <textarea
      placeholder="your message..."
      v-model="message"
      @keydown.enter.exact.prevent="sendMessage"
    />
    <input 
      id="files"
      ref="files" 
      type="file"
      multiple 
      @change="handleFilesUpload"
    />
    <button v-if="message" @click="handleFilesUpload">Send</button>
  </div>
</template>

<script>
import { SendbirdAction } from '@/sendbird/SendbirdAction'

export default {
  name: 'MessageInput',
  data() {
    return {
      message: '',
    }
  },
  methods: {
    sendMessage: function (event) {
      if (event.isComposing) {
        return
      }
      SendbirdAction.getInstance()
        .sendUserMessage(this.message)
        .then((message) => {
          this.$emit('addInputMessage', message)
          this.message = ''
        })
    },

     handleFilesUpload: function (event) {
      const sendFile = event.target.files[0]
      console.log(event.target.files[0]);
      SendbirdAction.getInstance()
      .sendFileMessage(sendFile)
        .then((message) => {
          this.$emit('addInputFile', message)
          this.message = sendFile
        })
    },
  },
  
}
</script>

MessageLog.vue

<template>
  <div class="message-log">
    <ul v-if="msg.itemList.length > 0">
      <li
        class="chat-item"
        v-for="message in msg.itemList"
        :key="message.messageId"
      >
        <p>{{ message.sender.nickname }}</p>
        <div style="white-space: pre-wrap">{{ message.message }}</div>
        <p>{{ convertDate(message.createdAt) }}</p>
      </li>
    </ul>
  </div>
</template>

修复建议

1. 修正SendbirdAction中回调参数命名冲突

Sendbird的channel.sendFileMessage回调第一个参数是上传后的消息对象,不是传入的file,当前代码用file作为参数名会覆盖外部的file变量,导致resolve的对象错误。修改如下:

sendFileMessage(file) {
  const fileMessageParams = this.sb.FileMessageParams();
  fileMessageParams.file = file;

  return new Promise((resolve, reject) => { 
    // 将回调参数名改为message,避免冲突
    this.channel.sendFileMessage(fileMessageParams, (message, error) => {
      error ? reject(error) : resolve(message)
    })
  })
}

2. 修复MessageInput的文件上传触发逻辑

当前按钮点击调用handleFilesUpload时,无法获取input的文件(因为handleFilesUpload依赖input的change事件对象),需拆分文件选择和上传操作:

<template>
  <div>
    <textarea
      placeholder="your message..."
      v-model="message"
      @keydown.enter.exact.prevent="sendMessage"
    />
    <!-- 隐藏原生input,用按钮触发选择 -->
    <input 
      id="files"
      ref="files" 
      type="file"
      accept="image/*" <!-- 限制仅图片文件 -->
      @change="handleFileSelect"
      style="display: none"
    />
    <button @click="$refs.files.click()">选择图片</button>
    <!-- 有选中文件时显示发送按钮 -->
    <button v-if="selectedFile" @click="uploadFile">发送图片</button>
  </div>
</template>

<script>
import { SendbirdAction } from '@/sendbird/SendbirdAction'

export default {
  name: 'MessageInput',
  data() {
    return {
      message: '',
      selectedFile: null // 存储选中的文件
    }
  },
  methods: {
    sendMessage(event) {
      if (event.isComposing) return;
      SendbirdAction.getInstance()
        .sendUserMessage(this.message)
        .then((message) => {
          this.$emit('addInputMessage', message);
          this.message = '';
        })
        .catch(err => console.error('发送消息失败:', err));
    },

    // 仅处理文件选择
    handleFileSelect(event) {
      this.selectedFile = event.target.files[0];
      console.log('选中文件:', this.selectedFile);
    },

    // 单独处理文件上传
    uploadFile() {
      if (!this.selectedFile) return;
      SendbirdAction.getInstance()
        .sendFileMessage(this.selectedFile)
        .then((message) => {
          this.$emit('addInputFile', message);
          this.selectedFile = null;
          // 清空input值,避免重复选同一文件不触发change事件
          this.$refs.files.value = '';
        })
        .catch(err => console.error('文件上传失败:', err));
    }
  }
}
</script>

3. 完善MessageLog的文件消息展示

文件消息的内容不在message字段,而是存储在url、name、mimeType等属性中,需判断消息类型后渲染:

<template>
  <div class="message-log">
    <ul v-if="msg.itemList.length > 0">
      <li
        class="chat-item"
        v-for="message in msg.itemList"
        :key="message.messageId"
      >
        <p>{{ message.sender.nickname }}</p>
        <!-- 区分文本消息和文件消息 -->
        <div v-if="message.type === 'file'">
          <span>{{ message.name }}</span>
          <!-- 图片文件显示预览 -->
          <img 
            v-if="message.mimeType.startsWith('image/')" 
            :src="message.url" 
            alt="图片消息" 
            style="max-width: 200px; max-height: 200px; margin-top: 8px;"
          />
          <!-- 非图片文件显示下载链接 -->
          <a 
            v-else 
            :href="message.url" 
            target="_blank" 
            style="display: block; margin-top: 8px;"
          >点击下载</a>
        </div>
        <div v-else style="white-space: pre-wrap">{{ message.message }}</div>
        <p style="font-size: 12px; color: #999;">{{ convertDate(message.createdAt) }}</p>
      </li>
    </ul>
  </div>
</template>

4. 确保父组件正确接收文件消息

父组件需同时监听addInputMessage和addInputFile事件,将文件消息加入到聊天列表:

<!-- 父组件模板 -->
<MessageInput 
  @addInputMessage="addMessageToList"
  @addInputFile="addMessageToList"
/>

<!-- 父组件script -->
methods: {
  addMessageToList(message) {
    this.msg.itemList.push(message);
    // 可选:滚动到最新消息
    this.$nextTick(() => {
      const logEl = this.$refs.messageLog;
      logEl.scrollTop = logEl.scrollHeight;
    });
  }
}

5. 补充错误捕获

在所有异步操作中添加catch,方便排查上传失败原因,比如网络问题、Sendbird权限配置等。


内容的提问来源于stack exchange,提问作者dlkhjs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 20:57:21