最近在用uniapp做app,中间涉及到了聊天功能,我在uni插件市场找到了集成tim腾讯即时通讯的模板:https://ext.dcloud.net.cn/plugin?id=1421
但作者没有实现上传图片消息的功能,自己搞了下,坑真多
首先,uniapp中选择图片用uni.chooseImage,返回:
返回一些blob的url,但是tim要求发图片必须使用dom对象或者File对象
这就只能把blob变成file对象了。
关于file对象的探索看这个:https://blog.csdn.net/lianzhang861/article/details/80283120
关于创建File对象,可以这样:
var file1=new File([blob], "aa.png",{type:"image/jpg"}); //第一个参数是Blob对象或者dataUrl,第二个参数是文件名,三个参数可选,规定文件类型
注意:第一个参数必须是对象,不能是转换成的字符串,比如uniapp或者微信小程序的chooseImage方法返回的blob的url,他是一个字符串,这样生成的File对象只是将url字符串变成文件了,不是文件本身!!!
想把blob字符串变成Blob对象,可以用es6的:const blob = await fetch(image.path).then(r => r.blob())
或者用传统的XHR或者ajax也行,就是把blob对象根据url给获取出来就行。
实例:
getImage(type){
this.hideDrawer();
uni.chooseImage({
sourceType:[type],
sizeType: ['original'/* , 'compressed' */], //可以指定是原图还是压缩图,默认二者都有
success: (res)=>{
console.log("!!!!!!!!!!!!!!!!!!!!")
console.log(res)
for(let i=0;i<res.tempFilePaths.length;i++){
//res.name="aa.png"
uni.getImageInfo({
src: res.tempFilePaths[i],
success: async (image)=>{
const blob = await fetch(image.path).then(r => r.blob())
var file1=new File([blob], res.tempFiles[i].name,{type:blob.type});
//file1.type="image/jpeg";
let msg = {url:res.tempFilePaths[i],file:file1,w:image.width,h:image.height};
this.sendMsg(msg,'img');
}
});
}
}
});
},
// 发送消息
sendMsg(content,type){
console.log(content)
let message
if(type=="text"){
message= this.tim.createTextMessage({
to: this.toUserId,
conversationType: 'C2C',
payload: {
text: content.text
}
});
}else if(type=="img"){
message = this.tim.createImageMessage({
to: this.toUserId,
conversationType: 'C2C',
// 消息优先级,用于群聊(v2.4.2起支持)。如果某个群的消息超过了频率限制,后台会优先下发高优先级的消息,详细请参考:https://cloud.tencent.com/document/product/269/3663#.E6.B6.88.E6.81.AF.E4.BC.98.E5.85.88.E7.BA.A7.E4.B8.8E.E9.A2.91.E7.8E.87.E6.8E.A7.E5.88.B6)
// 支持的枚举值:TIM.TYPES.MSG_PRIORITY_HIGH, TIM.TYPES.MSG_PRIORITY_NORMAL(默认), TIM.TYPES.MSG_PRIORITY_LOW, TIM.TYPES.MSG_PRIORITY_LOWEST
// priority: TIM.TYPES.MSG_PRIORITY_NORMAL,
payload: {
file: content.file
},
onProgress: function(event) { console.log('file uploading:', event) }
});
}
this.$store.commit('pushCurrentMessageList', message)
let pomise = this.tim.sendMessage(message)
pomise.then(res=>{
console.log(res)
this.$nextTick(()=> {
// 滚动到底
this.scrollToView = res.data.message.ID
});
})
},
其实就是简单的blob转file而已,只不过从毫无头绪开始搞起,又看jdk源码都找资料的,一点点东西花了近两天的时间!!!
ps:
问题描述:
在uniapp h5版里面使用腾讯的即时通讯IM时,发现图片发送不了;
IM文档地址:TIM
查看 tim-js.js 源码发现,是由于uniapp内部封装有微信小程序的 wx 对象,导致 tim-js.js 即使在浏览器环境下也错误的判断成了小程序环境,导致上传插件 cos-js-sdk-v5 出现加载失败问题;
tim-js.js翻车地点:
上图红框内的判断导致变量 Oa(不一定是Oa,因为每次代码压缩混淆都会不一样) 在h5环境下始终未true;可以通过搜索canIUse字符定位到这里;
解决办法:
将上图红框代码更改为下面代码即可:
Oa = "undefined" == typeof window && "undefined" != typeof wx && "function" == typeof wx.getSystemInfoSync && "function" == typeof wx.canIUse,
ps:
上次闹得只能用于h5端,因为uniapp用的是js的sdk,tim要求你上传file对象,但是在app中,无法将path转行成js中的file对象传给tim,这样的话只能换一个方式了。
解决办法:
思路:将要发送的图片上传到自己的服务器或者oss啥的就行了,返回一个url,将url拼到自定义消息中即可
上传图片的步骤我就省略了,这里说的是上传后返回一个url,再创建:
message = this.tim.createCustomMessage({
to: this.toUserId,
conversationType: 'C2C',
// 消息优先级,用于群聊(v2.4.2起支持)。如果某个群的消息超过了频率限制,后台会优先下发高优先级的消息,详细请参考:https://cloud.tencent.com/document/product/269/3663#.E6.B6.88.E6.81.AF.E4.BC.98.E5.85.88.E7.BA.A7.E4.B8.8E.E9.A2.91.E7.8E.87.E6.8E.A7.E5.88.B6)
// 支持的枚举值:TIM.TYPES.MSG_PRIORITY_HIGH, TIM.TYPES.MSG_PRIORITY_NORMAL(默认), TIM.TYPES.MSG_PRIORITY_LOW, TIM.TYPES.MSG_PRIORITY_LOWEST
// priority: TIM.TYPES.MSG_PRIORITY_HIGH,
payload: {
data: 'chatFile', // 用于标识该消息类型
description: content, // 用于装载url
extension: ''
}
});
这样返回message中就有了payload信息:
在消息队列中判断消息类型,把description赋值给img就完事
<view v-if="item.type=='TIMCustomElem'" class="bubble img" @tap="showPic(item.payload.description)">
<image :src="item.payload.description" :style="{'width': 100+'px','height': 100+'px'}"></image>
</view>
至于其他类型的比如视频音频啥的,都可以使用这种方法,可以判断data的标识,也可以判断url的文件类型,区分不同的消息展示方式