在vue2项目中使用腾讯云IM及常见坑
gogogo~
先放上官方文档的链接
即时通信 IM 快速集成方案(Web)-含 UI 快速集成方案(荐)-文档中心-腾讯云 (tencent.com)
由于目前官方文档已经将含UI的快速集成方案变为了vue3+TS,而且在很多地方的解释阅读起来可能有一定的难度,所以有了这篇文章
这是demo文件结构
安装依赖
首先安装相应的IM SDK依赖
// 聊天插件
npm install tim-js-sdk --save
// 上传插件
npm install tim-upload-plugin --saves
demo项目中直接用的js文件,在sdk文件夹中
创建实例
创建tim.js文件用于创建相关实例
import TIM from 'tim-js-sdk'
import TIMUploadPlugin from 'tim-upload-plugin'
// 初始化 SDK 实例
const tim = TIM.create({
SDKAppID: 0 // 接入时需要将0替换为您的即时通信 IM 应用的 SDKAppID
})
window.setLogLevel = tim.setLogLevel
// 无日志级别
tim.setLogLevel(4)
// 注册 cos
tim.registerPlugin({ 'tim-upload-plugin':TIMUploadPlugin })
export default tim
生成用户信息
SDKAppID需要在官网中创建项目生成
这时第一个问题来了,想要实现聊天功能,必须要有用户ID和对应的密码,即userID和userSig,官方文档也对我们进行了提示,测试环境可以使用客户端根据userID计算UserSig,项目上线要采用服务端计算UserSig。因此对于上线的情况,前端只需要调接口即可,我们现在针对客户端生成。
即时通信 IM 生成 UserSig-服务端 API-文档中心-腾讯云 (tencent.com)
上面的是官方文档创建SDKAppID以及生成UserSig的链接
选择该项
进去之后会发现GenerateTestUserSig.js该文件还引入了lib-generate-test-usersig.min.js文件,因此我们要返回文档的上级TIMSDK/Web/Demo/debug at master · TencentCloud/TIMSDK · GitHub将lib-generate-test-usersig.min.js也下载下来,存放在项目的public/debug文件中
在GenerateTestUserSig.js填入SDKAPPID,过期时间EXPIRETIME,以及项目的密钥SECRETKEY,即可生成userSig
调用函数失败的问题
一般情况下我们的版本比较新,直接引入GenerateTestUserSig.js的函数会报错,因此采用如下方法解决,在debug文件夹下创建三个文件
GenerateTestUserSig.js
// GenerateTestUserSig.js
import * as LibGenerateTestUserSig from './lib-generate-test-usersig.min.js';
const SDKAPPID = 0; // 输入自己的
const EXPIRETIME = 604800; // 过期时间
const SECRETKEY = 'xxx'; // 输入自己的
function genTestUserSig(userID) {
const generator = new LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME);
const userSig = generator.genTestUserSig(userID);
return {
sdkAppID: SDKAPPID,
userSig,
};
}
export default genTestUserSig;
export {
SDKAPPID,
EXPIRETIME,
};
index.js
// index.js
import genTestUserSig, { SDKAPPID, EXPIRETIME } from './GenerateTestUserSig';
export {
genTestUserSig,
SDKAPPID,
EXPIRETIME,
};
lib-generate-test-usersig.min.js
使用上文中的即可
本项目的用户信息会存入vuex中,因此只需要在登录时导入一次genTestUserSig即可
import { genTestUserSig } from '../../../public/debug/index'
登录
需要生成的信息准备好后,可以开始完成登录模块了
登录模块的具体内容参考官方文档,只需要注意调用GenerateTestUserSig.js中的函数根据用户名生成usersig即可
登录成功后将用户的登录状态、登录信息放入vuex中
初始化
使用this.tim.on监听
触发对应事件,更新vuex中的信息,在actions调用tim的api对消息进行处理
就到了side-bar组件和current-conversation组件,side-bar用于切换功能,current-conversation是聊天的主界面
后续想实现什么功能都可以参考官方文档
自定义消息
项目中要求实现聊天功能,发送面试邀约信息,适合采用自定义消息的方式
参考官方文档
message-send-box组件
调用tim.createTextMessage(options);
创建消息
to和conversationType在选中聊天对象时就已经保存在vuex中,直接获取即可
关键在于payload字段
data字段用来标识,extension用于存放信息
const message = this.tim.createCustomMessage({
to: this.toAccount,
conversationType: this.currentConversationType,
payload: {
// data作为字段表示,可自定义
data:'interviewInvitation',
// extension中存放了要显示的信息以及interviewId
// 之后如果点击查看可以根据interviewId跳转界面渲染内容
extension: JSON.stringify({
title: "面试邀请",
description: "点击查看",
imageUrl: '',
interviewId: invideId
}),
},
cloudCustomData:this.form
})
调用sendMessage
发送消息
this.$store.commit('pushCurrentMessageList', message)
this.tim.sendMessage(message).catch((error) => {
this.$store.commit('showMessage', {
type: 'error',
message: error.message,
})
})
message-item组件
用来判断消息类型,如果是自定义消息就渲染custom-element组件
<custom-element
v-else-if="message.type === TIM.TYPES.MSG_CUSTOM"
:isMine="isMine"
:payload="message.payload"
:message="message"
/>
custom-element组件
当点击自定义消息时,根据保存的面试id跳转到对应路由并根据id渲染界面
// custom-element组件
<template>
<message-bubble :isMine=isMine :message=message>
<div class="custom-element-wrapper">
<div class="survey" v-if="this.payload.data === 'interviewInvitation'" @click="clickInvite(renderDom.interviewId)">
<div class="title">{{renderDom.title}}</div>
<div class="suggestion">{{renderDom.description}}</div>
</div>
<span class="text" title="您可以自行解析自定义消息" v-else>
<template v-if="text.isFromGroupLive && text.isFromGroupLive === 1">
<message-group-live-status :liveInfo='text' />
</template>
<template v-else>{{text}}</template>
</span>
</div>
</message-bubble>
</template>
<script>
import { mapState } from 'vuex'
import MessageBubble from '../message-bubble'
import MessageGroupLiveStatus from '../message-group-live-status'
export default {
name: 'CustomElement',
props: {
payload: {
type: Object,
required: true
},
message: {
type: Object,
required: true
},
isMine: {
type: Boolean
}
},
components: {
MessageBubble,
MessageGroupLiveStatus
},
data(){
return{
}
},
computed: {
...mapState({
currentUserProfile: state => state.user.currentUserProfile
}),
text() {
return this.translateCustomMessage(this.payload)
},
renderDom(){
return JSON.parse(this.payload.extension)
}
},
methods: {
translateCustomMessage(payload) {
let videoPayload = {}
try{
videoPayload = JSON.parse(payload.data)
} catch(e) {
videoPayload = {}
}
if (payload.data === 'group_create') {
return `${payload.extension}`
}
if (videoPayload.roomId) {
videoPayload.roomId = videoPayload.roomId.toString()
videoPayload.isFromGroupLive = 1
return videoPayload
}
if(payload.text) {
return payload.text
}
if(payload.data == 'interviewInvitation'){
const extension = JSON.parse(payload.extension)
}
else{
return '[未知消息]'
}
},
clickInvite(interviewId){
this.$router.push('/interviewManage/interviewDetail/'+interviewId)
}
}
}
</script>