页面显示
1.无ui集成方案
1.1 首先下来依赖
//初始化
npm init
// IM Web SDK
// 从v2.11.2起,SDK 支持了 WebSocket,推荐接入;v2.10.2及以下版本,使用 HTTP
npm install tim-js-sdk --save
// 发送图片、文件等消息需要腾讯云即时通信 IM 上传插件
npm install tim-upload-plugin --save
// 拦截或替换敏感词需要本地审核插件
npm install tim-profanity-filter-plugin --save
1.2 创建tim.js
import TIM from 'tim-js-sdk/tim-js-friendship.js'
import TIMUploadPlugin from 'tim-upload-plugin';
import TIMProfanityFilterPlugin from 'tim-profanity-filter-plugin';
// import COS from "cos-js-sdk-v5";
const options = {
SDKAppID: 1600024346
// 接入时需要将0替换为您的即时通信应用的 SDKAppID
};
// 创建 SDK 实例,TIM.create() 方法对于同一个 SDKAppID 只会返回同一份实例
const tim = TIM.create(options); // SDK 实例通常用 tim 表示
// tim.setLogLevel(0);
const TIMData = TIM
// 注册腾讯云即时通信 IM 上传插件
tim.registerPlugin({
‘tim-upload-plugin’: TIMUploadPlugin
});
// 注册腾讯云即时通信 IM 本地审核插件
tim.registerPlugin({
'tim-profanity-filter-plugin': TIMProfanityFilterPlugin
});
// 注册 COS SDK 插件
// tim.registerPlugin({'cos-js-sdk': COS});
/* eslint-disable require-jsdoc */
function genTestUserSig(userID) {
const SDKAPPID = 1600024346;
const EXPIRETIME = 604800;
const SECRETKEY = ‘a03e633a7f9e49784a8f1b1d87ebc4d930be70544e13822bdd8f9a0af40acc1’;
const generator = new LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME);
const userSig = generator.genTestUserSig(userID);
return {
sdkAppId: SDKAPPID,
userSig: userSig
};
}
export default {
tim,
TIMData,
genTestUserSig
}
1.3 在main.js导入
import tim from './utils/tim.js'
import TIM from 'tim-js-sdk/tim-js-friendship.js'
Vue.prototype.tim = tim.tim //tim sdk 引入后生成的tim服务
Vue.prototype.$TIM = TIM //tim 的状态/事件 常量
2.1 在登录接口存储用户信息
//用户信息
user() {
this.$helper.apiPost(this.$api.tab.user).then(ret => {
if (ret.data.code == 200) {
this.info = ret.data.data
//根据返回的userID 以及 userSig 登录tim
uni.setStorageSync('uid', ret.data.data.username)
//这里我叫后端返回了一个userSing
uni.setStorageSync('uid_sig', ret.data.data.user_sig)
console.log(this.info, '122332211');
this.tim.login({
userID: this.info.username,
userSig: this.info.user_sig
}).then((imResponse) => {
this.$helper.showToast('登录成功')
setTimeout(() => {
uni.switchTab({
url: '/pages/tab/home'
})
}, 500)
})
}
})
},
2.2 进入首页
data() {
return {
userID: uni.getStorageSync('uid'),
userSig: uni.getStorageSync('uid_sig'),
};
},
onLoad() {
this.cosImLogin()
},
methods: {
cosImLogin() {
console.log(this.userID, 'this.userID');
console.log(this.userSig, 'this.userSig');
if (!this.userID.length || !this.userSig.length) return
this.tim.login({
userID: this.userID,
userSig: this.userSig
}).then((res) => {
this.loginTUICallKit()
}).catch((err) => {
console.log("报错", err)
})
},
loginTUICallKit() {
const options = {
SDKAppID: 1600024346, // 请替换为步骤一取到的 SDKAppID
userID: this.userID, // 请替换为您的 UserID
userSig: this.userSig, // 您可以在控制台中计算一个 UserSig 并填在这个位置
};
this.$TUICallKit.login(options, (res) => {
if (res.code === 0) {
console.log('login success');
this.$TUICallKit.enableFloatWindow(true); // 开启小浮窗
} else {
console.log(`login failed, error message = ${res.msg}`);
}
});
},
}
2.3 我的好友列表
export default {
data() {
return {
friends: []
};
},
onLoad() {
this.friendList();
},
methods: {
openConversation(name, userID) {
// userID:电话号码 username:昵称
//跳转到聊天页面(聊天页面自定义头部所以要携带昵称)
this.$helper.toPage('/pages/active/chat?name=' + name + '&userID=' + userID);
},
//我的好友
async friendList() {
let res = await this.$helper.apiPost(this.$api.user.friend_list);
this.friends = res.data.data;
console.log(this.friends);
}
}
};
3.1 聊天页面
3.1.1 对话内容
3.1.1 对话内容
<view class="msg-content-list">
<mescroll-uni ref="mescrollRef" :fixed="false" :down="downOption" @init="mescrollInit" @down="downCallback" @up="upCallback">
<view>
<view class="msg-content-item" v-for="(item, index) in msgList">
<view class="time-slot" v-if="item.isShowTime || index == 0">
{{getShowTimePipe(item.time) || ''}}
</view>
<!-- 个人开始 -->
<view>
<view class="content-from msg" v-if="item.flow == 'in'">
<image class="msg-image left-head" :src="item.avatar" />
<!-- 每条消息内容 -- left -->
<view class="content-my-left-box">
<!-- 展示文本 -->
<view class="content-my-left-text" v-if="item.type == 'TIMTextElem'">
<rich-text :nodes="nodesFliter(item.payload.text)"></rich-text>
</view>
<!-- 展示图片 -->
<image class="content-my-left-img" :style="`height:${item.payload.imageInfoArray[1].height}px; width: ${item.payload.imageInfoArray[1].width}px;`" :src="item.payload.imageInfoArray[1].imageUrl" mode="widthFix" v-else-if="item.type == 'TIMImageElem'" @click="onPreviewImg(item.payload.imageInfoArray[1].imageUrl)"></image>
<!-- 展示视频 -->
<MyVideo class="content-my-video" v-else-if="item.type == 'TIMVideoFileElem'" :videoUrl="item.payload.remoteVideoUrl" />
</view>
<!-- 每条消息内容 -- left -->
</view>
<view class="content-my msg" v-else-if="item.flow == 'out'">
<!-- 每条消息内容 -- right -->
<view class="content-my-right-box">
<!-- 展示文本 -->
<view class="content-my-right-text" v-if="item.type == 'TIMTextElem'">
rich-text :nodes="nodesFliter(item.payload.text)"></rich-text>
</view>
<!-- 展示图片 -->
<image class="content-my-right-img" :style="`height: ${item.payload.imageInfoArray[1].height*2}rpx; width: ${item.payload.imageInfoArray[1].width*2}rpx;`":src="item.payload.imageInfoArray[1].imageUrl" mode="widthFix" v-else-if="item.type == 'TIMImageElem'" @click="onPreviewImg(item.payload.imageInfoArray[1].imageUrl)"></image>
<!-- 展示视频 -->
<MyVideo class="content-my-video" v-else-if="item.type == 'TIMVideoFileElem'" :videoUrl="item.payload.remoteVideoUrl" />
</view>
<!-- 每条消息内容 -- right -->
<image class="msg-image right-head" :src="item.avatar " />
</view>
</view>
<!-- 个人结束 -->
</view>
</view>
</mescroll-uni>
</view>
3.2 底部输入框
3.2 底部输入框
<view class="bottom fixed" @click="getBottomHeight()" :style="{bottom: changeBottomVal}">
<view class="flex-center-between">
<image @click="imgBtn" src="/static/images/home/1086.png" mode=""></image>
// @keyboardheightchange 监听键盘高度
<input :adjust-position="false" @keyboardheightchange="keyboardheightchange" class="save-inp" v-model="msgText" :focus="focus" type="text" @confirm="sendBtn">
<view class="send" @click="sendBtn">发送</view>
</view>
</view>
3.1.2 js代码
3.1.2 js代码
data() {
return {
top: uni.getStorageSync('safeArea').top,
name: '',
bottomImg: false,
username: '',
changeBottomVal: '',//键盘高度
bottomHeight: '', //底部高度
msgList: [], // 会话消息列表
msgText: '', // 文字消息
message: {}, // 发送消息对象
timUserInfo: {}, // 会话对象用户信息
msgUserData: {}, // 会话对象信息
focus: false,
downOption: {
auto: false,
textInOffset: '拉取历史记录',
textOutOffset: '',
textLoading: '拉取中...'
},
};
},
onShow() {
this.getTimeSlot()
// 获取会话数据
this.getListMsg()
},
onLoad(e) {
this.tim.on(this.$TIM.EVENT.MESSAGE_RECEIVED, (event) => {
if (event.data[0].type == "TIMSoundElem") {
this.getListMsg()
this.getTimeSlot()
} else {
let arr = event.data.filter((res) => res.conversationID == (this.isGroup ? `GROUP${this.msgData.groupID}` :
`C2C${this.msgUserData.userID}`))
this.msgList.push(...arr)
this.getTimeSlot()
// 获取底部高度
this.getBottomHeight(false)
}
})
this.name = e.name;
this.username = e.username;
this.msgUserData = e
// 已读会话
this.inRead()
// 获取底部高度
this.getBottomHeight(false)
},
methods: {
//键盘高度
keyboardheightchange(e) {
this.changeBottomVal = e.detail.height + 'px'
},
getBottomHeight() {
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query.select('.bottom').boundingClientRect(data => {
this.bottomHeight = data.height
console.log(data.height, 'data.height');
}).exec();
this.$nextTick(() => {
uni.pageScrollTo({
scrollTop: 9999,
duration: 100
})
})
})
},
// 预览图片
onPreviewImg(image) {
uni.previewImage({
urls: [image],
fail: function(err) {}
})
},
imgBtn() {
this.bottomImg = !this.bottomImg
},
// 发送拍摄或者上传视频
sendMsgVideo() {
uni.chooseVideo({
success: (res) => {
this.message = this.tim.createVideoMessage({
to: this.msgUserData.userID,
conversationType: 'C2C',
payload: {
file: res
},
onProgress: (event) => {}
});
this.tim.sendMessage(this.message).then((res) => {
this.msgList.push(res.data.message)
// 获取底部高度
this.getBottomHeight(false)
})
}
})
},
// 发送拍摄或者上传图片
sendMsgImage() {
uni.chooseImage({
count: 1,
mediaType: ['image'], // 图片
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
success: (res) => {
this.message = this.tim.createImageMessage({
to: this.msgUserData.userID,
conversationType: 'C2C',
payload: {
file: res
},
onProgress: function(event) {}
});
this.tim.sendMessage(this.message).then((res) => {
this.msgList.push(res.data.message)
// 获取底部高度
this.getBottomHeight(false)
})
}
});
},
// 判断是否有十分钟的时间间隔
getTimeSlot() {
setTimeout(() => {
this.msgList.forEach((res, index) => {
let i = this.msgList.length - (index + 2) <= 0 ? 0 : this.msgList.length - (index + 2)
let j = this.msgList.length - (index + 1) <= 0 ? 0 : this.msgList.length - (index + 1)
let time1 = this.$time.getNowDate(this.msgList[i].time * 1000)
let time2 = this.$time.getNowDate(this.msgList[j].time * 1000)
if (this.$time.GetDateDiff(time2, time1, 'minute') <= -5) {
this.$set(this.msgList[j], 'isShowTime', true)
}
})
}, 300)
},
// 获取会话列表
getListMsg(isDown = false) {
// 用于拉取历史聊天数据
let parmas = {
conversationID: `C2C${this.msgUserData.userID}`,
nextReqMessageID: this.nextReqMessageID
}
// 用于拉取目前聊天数据
let data = {
conversationID: `C2C${this.msgUserData.userID}`,
}
this.tim.getMessageList(isDown ? parmas : data).then((res) => {
this.nextReqMessageID = res.data.nextReqMessageID
console.log(res, '11122111221');
if (!this.nextReqMessageID.length || this.nextReqMessageID == '-1') this.mescroll.lockDownScroll(true)
if (isDown) {
this.msgList = res.data.messageList.concat(this.msgList)
this.mescroll.endDownScroll()
} else {
this.msgList = res.data.messageList
}
});
this.timeOut = setTimeout(() => {
uni.hideLoading()
if (!isDown) {
uni.pageScrollTo({
scrollTop: 9999,
duration: 100
})
}
this.$forceUpdate()
}, 800)
},
inRead() {
// 将某会话下所有未读消息已读上报
this.tim.setMessageRead({
conversationID: `C2C${this.msgUserData.userID}`
})
},
//聊天的节点加上外层的div
nodesFliter(str) {
let nodeStr = '<div style="display: flex; align-items: center;word-wrap:break-word; width: auto;">' + str +
'</div>'
return nodeStr
},
getShowTimePipe(time) {
return this.$time.showTimePipe(time * 1000)
},
// 发送文本
sendMsgText() {
this.msgText = this.msgText.trim()
console.log(this.msgText, '111111');
if (this.msgText.length == '') {
uni.showToast({
title: "发送消息不能为空",
icon: "none"
})
return
}
// 1. 创建消息实例,接口返回的实例可以上屏
this.message = this.tim.createTextMessage({
to: this.msgUserData.userID,
conversationType: 'C2C',
payload: {
text: this.msgText
},
});
this.tim.sendMessage(this.message).then((res) => {
this.msgList.push(res.data.message)
this.focus = true
this.msgText = ""
// 获取底部高度
this.getBottomHeight(false)
})
},
sendBtn() {
this.sendMsgText()
}
}
4.1 消息列表
4.1.1 html
<view>
<view v-for="(item, index) in list" :key="index" @click="goToMessage(item.userProfile.nick,item.userProfile.userID,index)">
<view class="pop flex-center-between">
<view class="name flex">
<image :src="item.userProfile.avatar" mode=""></image>
<view class="tian">
<view>{{item.userProfile.nick}}</view>
<span>
<rich-text :nodes="nodesFliter(item.lastMessage.messageForShow)"></rich-text>
</span>
</view>
</view>
//未读消息
<view class="red" v-if="item.unreadCount">{{item.unreadCount}}</view>
</view>
<view class="line"></view>
</view>
</view>
4.2.2 js
export default {
data() {
return {
top: uni.getStorageSync('safeArea').top,
list: [],
isTips: true
};
},
onLoad() {
this.getList()
},
onShow() {
this.getList()
},
methods: {
//聊天的节点加上外层的div
nodesFliter(str) {
let nodeStr = '<div style="align-items: center;word-wrap:break-word;">' + str + '</div>'
return nodeStr
},
goToMessage(name, userID, index) {
this.$helper.toPage('/pages/active/chat?name=' + name + '&userID=' + userID );
// this.list[index].unreadCount = 0
},
getList() {
// 获取全量的会话列表
this.tim.getConversationList().then((res) => {
this.list = res.data.conversationList
// console.log(this.list, '1111');
console.log(this.list, '1111');
this.list = this.list.filter((res) => res.type != "@TIM#SYSTEM")
this.getFriend()
})
},
getFriend() {
this.tim.getFriendApplicationList().then(res => {
this.friendNum = res.data.unreadCount
})
},
}
};
版权归原作者 次贝。 所有, 如有侵权,请联系我们删除。