小程序对接腾讯云IM即时聊天
步骤如下
- 下载sdk并引入(tim-wx-sdk、cos-wx-sdk-v5)
- 建立监听(Event.js)
- 初始化IM
- 登录IM
- 监听IM各个状态钩子
- 聊天(获取聊天记录、发送消息、接受消息、发送图片、发送自定义消息)
一:下载sdk
一:下载sdk
(1)npm方式下载
// IM 小程序 SDK
npm install tim-wx-sdk --save
// 发送图片、文件等消息需要的 COS SDK
npm install cos-wx-sdk-v5 --save
(2)直接下载js文件
下载链接(https://cloud.tencent.com/document/product/269/36887)
或(文章最后会提供完整代码)
二:初始化IM
- 开发过程遇到的其中一个问题就是数据同步,应该是有很多方法的,这儿采用的是引入一个监听器,在app.js里面,将Event监听器挂载到wx对象上
- 初始化im
- 登录im
//app.js
import Event from './plugin/tencentIM/event'
wx.event = new Event();
import {initTIM,loginTIM} from './plugin/im-init'
App({
require ($uri){
return require($uri)
},
onLaunch() {
initTIM(this.globalData);//初始化IM
loginTIM(this.globalData);//登录IM
},
globalData: {
TIM: null,
TIM_INIT:false
}
});
//im-init.js
import TIM from "tim-wx-sdk";//npm方式引入
import COS from "cos-wx-sdk-v5";//npm方式引入
let DATA_APP = getApp() && getApp().globalData || {};
let DATA_TIM = DATA_APP.TIM || {};
/**
* IM初始化
* @return null
*/
export function initTIM(item) {
let options = {
SDKAppID: '这里填写你自己SDKAppID'
};
if(item){
DATA_APP = item;
}
//避免重复创建im实例
if (DATA_APP.TIM_INIT) {
return
}
let DATA_TIM_READY = false;
// 创建 SDK 实例,`TIM.create()`方法对于同一个 `SDKAppID` 只会返回同一份实例
DATA_TIM = TIM.create(options);// SDK 实例通常用 DATA_TIM 表示
// 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明
DATA_TIM.setLogLevel(0); // 普通级别,日志量较多,接入时建议使用
// DATA_TIM.setLogLevel(1); // release 级别,SDK 输出关键信息,生产环境时建议使用
// 注册 COS SDK 插件 此处暂时隐藏有需求要传图片,文件等的请放开进行配置,记住头部引入
DATA_TIM.registerPlugin({'cos-wx-sdk': COS});
// 监听事件,例如:
DATA_TIM.on(TIM.EVENT.SDK_READY, function (event) {
//此回调函数中发布'conversationInit'对话列表初始化事件触发页面js中的
//需要注意的是DATA_TIM.getMessageList({})这个方法必须要在SDK_READY状态才能调用,所以要放在这个回调函数中
wx.event.emit('conversationList');// 会话列表的监听函数
wx.event.emit('conversationInit');// 聊天记录的监听函数
DATA_TIM_READY = true;
// 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
// event.name - TIM.EVENT.SDK_READY
});
DATA_TIM.on(TIM.EVENT.MESSAGE_RECEIVED, function (event) {
console.log('收到消息');
// 这里收到消息,调用setGlobalMsg方法来处理数据,传入方式标记为'received'接收消息
wx.event.emit('received', event) // 会话列表的监听函数
// setGlobalMsg(event,'received');
// 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面
// event.name - TIM.EVENT.MESSAGE_RECEIVED
// event.data - 存储 Message 对象的数组 - [Message]
});
DATA_TIM.on(TIM.EVENT.MESSAGE_REVOKED, function (event) {
// 收到消息被撤回的通知
// event.name - TIM.EVENT.MESSAGE_REVOKED
// event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isRevoked 属性值为 true
});
DATA_TIM.on(TIM.EVENT.MESSAGE_READ_BY_PEER, function (event) {
// SDK 收到对端已读消息的通知,即已读回执。使用前需要将 SDK 版本升级至 v2.7.0 或以上。仅支持单聊会话。
// event.name - TIM.EVENT.MESSAGE_READ_BY_PEER
// event.data - event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isPeerRead 属性值为 true
});
DATA_TIM.on(TIM.EVENT.CONVERSATION_LIST_UPDATED, function (event) {
// 收到会话列表更新通知,可通过遍历 event.data 获取会话列表数据并渲染到页面
// event.name - TIM.EVENT.CONVERSATION_LIST_UPDATED
// event.data - 存储 Conversation 对象的数组 - [Conversation]
if(DATA_TIM_READY){
wx.event.emit('conversationList') // 会话列表的监听函数
}
});
DATA_TIM.on(TIM.EVENT.GROUP_LIST_UPDATED, function (event) {
// 收到群组列表更新通知,可通过遍历 event.data 获取群组列表数据并渲染到页面
// event.name - TIM.EVENT.GROUP_LIST_UPDATED
// event.data - 存储 Group 对象的数组 - [Group]
});
DATA_TIM.on(TIM.EVENT.PROFILE_UPDATED, function (event) {
// 收到自己或好友的资料变更通知
// event.name - TIM.EVENT.PROFILE_UPDATED
// event.data - 存储 Profile 对象的数组 - [Profile]
});
DATA_TIM.on(TIM.EVENT.BLACKLIST_UPDATED, function (event) {
// 收到黑名单列表更新通知
// event.name - TIM.EVENT.BLACKLIST_UPDATED
// event.data - 存储 userID 的数组 - [userID]
});
DATA_TIM.on(TIM.EVENT.ERROR, function (event) {
// 收到 SDK 发生错误通知,可以获取错误码和错误信息
// event.name - TIM.EVENT.ERROR
// event.data.code - 错误码
// event.data.message - 错误信息
});
DATA_TIM.on(TIM.EVENT.SDK_NOT_READY, function (event) {
// 收到 SDK 进入 not ready 状态通知,此时 SDK 无法正常工作
// event.name - TIM.EVENT.SDK_NOT_READY
});
DATA_TIM.on(TIM.EVENT.KICKED_OUT, function (event) {
// 收到被踢下线通知
// event.name - TIM.EVENT.KICKED_OUT
// event.data.type - 被踢下线的原因,例如:
// - TIM.TYPES.KICKED_OUT_MULT_ACCOUNT 多实例登录被踢
// - TIM.TYPES.KICKED_OUT_MULT_DEVICE 多终端登录被踢
// - TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED 签名过期被踢 (v2.4.0起支持)。
});
DATA_TIM.on(TIM.EVENT.NET_STATE_CHANGE, function (event) {
// 网络状态发生改变(v2.5.0 起支持)。
// event.name - TIM.EVENT.NET_STATE_CHANGE
// event.data.state 当前网络状态,枚举值及说明如下:
// \- TIM.TYPES.NET_STATE_CONNECTED - 已接入网络
// \- TIM.TYPES.NET_STATE_CONNECTING - 连接中。很可能遇到网络抖动,SDK 在重试。接入侧可根据此状态提示“当前网络不稳定”或“连接中”
// \- TIM.TYPES.NET_STATE_DISCONNECTED - 未接入网络。接入侧可根据此状态提示“当前网络不可用”。SDK 仍会继续重试,若用户网络恢复,SDK 会自动同步消息
});
DATA_APP.TIM_INIT = true; //完成im实例创建后设置标志为true
DATA_APP.TIM = DATA_TIM;
console.log(DATA_APP)
}
/**
* IM登录
* @param {Object} item 数据
* @param {String} item.IM_ID
* @param {Date} item.IM_KEY
* @return null
*/
export function loginTIM(item) {
if(item){
DATA_TIM = item.TIM;
}
DATA_TIM.login({
userID: '从后端获取的IM userID',
userSig: '从后端获取的IM userSig'
}).then((imResponse) => {
console.log('IM登录成功:', imResponse);
}).catch((imError) => {
console.log('IM登录失败:', imError);
});
}
/**
* IM退出
* @return null
*/
export function loginOutTIM(item) {
if(item){
DATA_APP = item;
}
DATA_TIM.logout().then((imResponse) => {
console.log('IM退出成功:', imError);
}).catch((imError) => {
console.log('IM退出失败:', imError);
});
}
//Event.js
class Event {
/**
* on 方法把订阅者所想要订阅的事件及相应的回调函数记录在 Event 对象的 _cbs 属性中
*/
on(event, fn) {
if (typeof fn != "function") {
console.error('fn must be a function')
return
}
this._cbs = this._cbs || {};
(this._cbs[event] = this._cbs[event] || []).push(fn)
}
/**
* emit 方法接受一个事件名称参数,在 Event 对象的 _cbs 属性中取出对应的数组,并逐个执行里面的回调函数
*/
emit(event) {
this._cbs = this._cbs || {}
var callbacks = this._cbs[event], args
if (callbacks) {
callbacks = callbacks.slice(0)
args = [].slice.call(arguments, 1)
for (var i = 0, len = callbacks.length; i < len; i++) {
callbacks[i].apply(null, args)
}
}
}
/**
* off 方法接受事件名称和当初注册的回调函数作参数,在 Event 对象的 _cbs 属性中删除对应的回调函数。
*/
off(event, fn) {
this._cbs = this._cbs || {}
// all
if (!arguments.length) {
this._cbs = {}
return
}
var callbacks = this._cbs[event]
if (!callbacks) return
// remove all handlers
if (arguments.length === 1) {
delete this._cbs[event]
return
}
// remove specific handler
var cb
for (var i = 0, len = callbacks.length; i < len; i++) {
cb = callbacks[i]
if (cb === fn || cb.fn === fn) {
callbacks.splice(i, 1)
break
}
}
return
}
}
export default Event
三:一对一聊天
(1)index.wxml(图片部分自行补充)
<view class="chat-area">
<scroll-view scroll-into-view="{{ colToView }}" scroll-y="true" bindscrolltoupper="onLoadMore" bindtap="onHideSendMore">
<view class="loader-wrap" wx:if="{{showLoading}}" >
<text class="loader"></text>
</view>
<block wx:for="{{ arrMsg }}" wx:key="index">
<view class="{{ item.from === colUserId?'':'chat-his'}}">
<view wx:if="{{item.type == 'TIMImageElem'}}" class="chat-row flex-box-end" id="msg-{{index}}">
<view class="chat-img">
<image wx:if="{{item.status=='success'}}" class="chat-pic" mode="heightFix" lazy-load="{{true}}" src="{{item.payload.imageInfoArray[0].url}}" bindtap="previewImage" data-url="{{item.payload.imageInfoArray[2].url}}"></image>
<image wx:elif="{{item.status=='fail'}}" class="chat-pic" mode="heightFix" lazy-load="{{true}}" src="{{item.sendPic}}" data-url="{{item.payload.imageInfoArray[2].url}}">
<view class="chat-progress">发送失败</view>
</image>
<image wx:else class="chat-pic" mode="heightFix" lazy-load="{{true}}" src="{{item.sendPic}}" data-url="{{item.payload.imageInfoArray[2].url}}">
<view class="chat-progress">
<text class="loader"></text>
<text>{{colPercent}}%</text>
</view>
</image>
</view>
<view class="chat-head">
<image class="chat-headPortrait" src="/images/pic_1.png"></image>
</view>
</view>
<view wx:elif="{{item.type == 'TIMCustomElem'}}" class="chat-row flex-box-end" id="msg-{{index}}">
<view class="chat-main">
<view class="chat-msg chat-custom">
<view class="row">{{item.dataCustom.name}}就诊信息</view>
<view class="row">
<text class="item">{{item.dataCustom.sex}}</text>
<text class="item">{{item.dataCustom.age}}</text>
<text class="item">{{item.dataCustom.height}}</text>
<text class="item">{{item.dataCustom.weight}}</text>
</view>
<view class="row">
<view class="row-left">病情描述:</view>
<view class="row-right">{{item.dataCustom.desc}}</view>
</view>
<view class="row">
<view class="row-left">患病时长:</view>
<view class="row-right">{{item.dataCustom.descTime||'未知'}}</view>
</view>
<view class="row">
<view class="row-left">病史:</view>
<view class="row-right">{{item.dataCustom.history||'暂无'}}</view>
</view>
<view class="row">
<view class="row-left">过敏史:</view>
<view class="row-right">{{item.dataCustom.allergy||'无'}}</view>
</view>
</view>
<view class="chat-time">{{ item.timeFormat }}</view>
</view>
<view class="chat-head">
<image class="chat-headPortrait" src="/images/pic_1.png"></image>
</view>
</view>
<view wx:else class="chat-row flex-box-end" id="msg-{{index}}">
<view class="chat-main">
<!-- <view class="left-chat-name">{{ item.from }}</view>-->
<view class="chat-msg">{{ item.payload.text }}</view>
<view class="chat-time">{{ item.timeFormat }}</view>
</view>
<view class="chat-head">
<image class="chat-headPortrait" src="/images/pic_1.png"></image>
</view>
</view>
</view>
</block>
</scroll-view>
<view class="chat-footer">
<view class="chat-input-box">
<input bindinput='onInputMsg' bindconfirm='TIM_createMsg' value="{{colSendMsg}}" placeholder='输入内容' class="input" cursor-spacing="20"></input>
<view class='footer-send' bindtap='onShowSendMore'>
更多
</view>
</view>
<view class="open-more" wx:if="{{showSendMore}}">
<view class="open-more-item" bindtap="TIM_createPhoto" data-name="album">
<image src="/images/im-img.png" mode="widthFix" class="msg-img"></image>
<view class="msg-text">相册</view>
</view>
<view class="open-more-item" bindtap="TIM_createPhoto" data-name="camera">
<image src="/images/im-photo.png" class="msg-img" mode="widthFix"></image>
<view class="msg-text">拍摄</view>
</view>
<view class="open-more-item" bindtap="TIM_createMsgCustom" data-name="camera">
<image src="/images/im-edit.png" class="msg-img" mode="widthFix"></image>
<view class="msg-text">自定义消息</view>
</view>
</view>
</view>
</view>
(2)index.wxss
view,text,image{
box-sizing: border-box;
}
.flex-box-start{
display: flex;
justify-content: start;
}
.flex-box-end{
display: flex;
justify-content: flex-end;
}
.chat-area{
width: 100%;
height: calc(100vh - 120rpx);
background-color: #f9f9f9;
font-weight: 400;
/*padding-bottom: 140rpx;*/
}
.chat-area > scroll-view{
position: relative;
height: 100%;
padding: 20rpx 20rpx 10rpx 20rpx;
box-sizing: border-box;
}
.chat-his{
}
.chat-his .flex-box-end{
flex-direction: row-reverse;
justify-content: flex-start!important;
}
.chat-his .chat-main{
align-items: flex-start!important;
}
.chat-his .chat-msg{
background: #ffffff!important;
color: #000000;
}
.chat-his .chat-msg:before{
content: '';
position: absolute;
width: 0;
height: 0;
border-width: 14rpx 20rpx;
border-style: solid;
border-color: transparent white transparent transparent;
left: -40rpx;
top: 30rpx;
}
.chat-his .chat-msg:after{
display: none;
}
.chat-his .chat-head{
margin-right: 30rpx;
margin-left: 0!important;
}
.chat-his .chat-img{
justify-content: flex-start!important;
}
.chat-his .chat-custom .item:after{
background: #000000!important;
}
.chat-headPortrait{
width: 100%;
height: 100%;
border-radius: 50%;
}
.chat-head{
width: 100rpx;
height: 100rpx;
margin-left: 30rpx;
flex: none;
}
.chat-end{
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
color: #8B8B8B;
margin-bottom: 40rpx;
}
.chat-main{
width: 100%;
display: flex;
flex-direction: column;
align-items: flex-end;
}
.chat-row{
margin: 30rpx 0;
}
.chat-name{
font-size: 26rpx;
color: #7C7C7C;
padding-left: 20rpx;
margin-bottom: 10rpx;
}
.chat-time{
font-size: 24rpx;
color: #b7b7b7;
padding-left: 12rpx;
margin-top: 16rpx;
}
.chat-msg{
display: inline-block;
position: relative;
max-width: calc(100% - 100rpx);
background-color: #0093A2;
padding: 26rpx 30rpx;
border-radius: 10rpx;
font-size: 28rpx;
word-wrap: break-word;
color: #FEFEFE;
margin-left: 6rpx;
/*font-weight: bold;*/
min-height: 90rpx;
}
.chat-msg:after{
content: '';
position: absolute;
width: 0;
height: 0;
border-width: 14rpx 20rpx;
border-style: solid;
border-color: transparent transparent transparent #0093A2;
right: -40rpx;
top: 30rpx;
}
.chat-custom{
}
.chat-custom .row{
display: flex;
width: 100%;
margin: 10rpx 0;
}
.chat-custom .row-left{
width: 150rpx;
flex: none;
}
.chat-custom .row-right{
flex: auto;
white-space: initial;
}
.chat-custom .row .item{
position: relative;
margin-right: 32rpx;
}
.chat-custom .item:after{
content: '';
width: 2rpx;
height: 30rpx;
background: #ffffff;
position: absolute;
right: -16rpx;
top: 50%;
transform: translateY(-50%);
}
.chat-custom .row .item:last-child:after{
width: 0;
}
.btn-wrap{
display: flex;
flex-direction: column;
align-items: center;
}
.btn-wrap .item{
width: 80%;
display: flex;
align-items: center;
justify-content: center;
height: 100rpx;
margin: 20rpx 0;
border-radius: 20rpx;
background: dodgerblue;
color: white;
font-size: 40rpx;
font-weight: bold;
z-index: 9999;
}
/* 图片消息 */
.chat-img{
width: 100%;
margin: 30rpx 0;
display: flex;
flex-grow: 1;
justify-content: flex-end;
}
.chat-pic {
max-width: 360rpx;
height: 360rpx;
background-repeat: no-repeat;
background-size: center;
background-position: center;
border-radius: 4rpx;
position: relative;
}
.chat-progress{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: rgba(29, 29, 29, 0.548);
color: #fff;
}
@keyframes loader {
0% {
-webkit-transform:rotate(0deg);
transform:rotate(0deg);
}
100% {
-webkit-transform:rotate(360deg);
transform:rotate(360deg);
}
}
.loader {
border-top:8rpx solid rgba(0,0,0,0.1);
border-right:8rpx solid rgba(0,0,0,0.1);
border-bottom:8rpx solid rgba(0,0,0,0.1);
border-left:8rpx solid #555;
transform:translateZ(0);
animation:loader 600ms infinite linear;
transition:all 500ms ease;
opacity:1;
}
.loader,.loader:after {
border-radius:50%;
width:40rpx;
height:40rpx;
}
/* 底部样式 */
.chat-footer{
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background:rgba(248,248,248,1);
box-sizing: border-box;
}
.chat-input-box{
display: flex;
justify-content: space-between;
align-items: center;
background: #ffffff;
padding: 20rpx 25rpx;
}
.chat-wait{
display: flex;
align-items: center;
justify-content: center;
height: 120rpx;
background: #ffffff;
font-size: 26rpx;
}
.msg-icon{
width: 58rpx;
height: 58rpx;
}
.chat-input-box .input{
height:76rpx;
line-height: 76rpx;
background:rgba(255,255,255,1);
border: none;
border-radius:6rpx;
font-size: 30rpx;
padding:0 30rpx;
display: flex;
flex-direction: row;
align-items: center;
position: relative;
flex-grow: 1;
background: #F1F1F1;
}
.inputArea{
width: 100%;
height: 98%;
flex-grow: 1;
}
.placeHolder{
position: absolute;
font-size: 26rpx;
color: #cccccc;
height: 100%;
box-sizing: border-box;
top: 0;
z-index: 0;
}
.footer-send{
height: 76rpx;
border-radius: 12rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 26rpx;
margin-left: 20rpx;
padding: 0 10rpx;
}
.footer-send-item{
font-size: 60rpx;
font-weight: bold;
}
.footer-h{
position: fixed;
top: 100px;
}
.more{
display: flex;
justify-content: center;
align-items: center;
}
.more-text{
padding: 6rpx 14rpx;
background:rgba(216,216,216,1);
border-radius:4rpx;
color: #FFFFFF;
font-size: 20rpx;
margin: 30rpx auto;
}
.open-more{
display: flex;
flex-wrap: wrap;
padding: 40rpx 0;
min-height: 360rpx;
}
.open-more-item{
flex-basis: 25%;
display: flex;
flex-direction: column;
align-items: center;
justify-items: center;
}
.open-more-item .msg-img{
width: 100rpx;
height: 100rpx;
margin-bottom: 16rpx;
}
.open-more-item .msg-text{
font-size: 28rpx;
color: #888888;
}
.loader-wrap {
display: flex;
align-items: center;
justify-content: center;
height: 80rpx;
width: 100%;
opacity:1;
z-index:99;
color: #b7b7b7;
font-size: 28rpx;
}
.loader-tip{
background: #E7E7E7;
display: flex;
align-items: center;
justify-content: center;
color: #8B8B8B;
padding:20rpx 30rpx;
font-size: 24rpx;
border-radius: 6rpx;
}
.loader {
border-top:8rpx solid rgba(0,0,0,0.1);
border-right:8rpx solid rgba(0,0,0,0.1);
border-bottom:8rpx solid rgba(0,0,0,0.1);
border-left:8rpx solid #555;
transform:translateZ(0);
animation:loader 600ms infinite linear;
transition:all 500ms ease;
opacity:1;
}
.loader,.loader:after {
border-radius:50%;
width:40rpx;
height:40rpx;
}
@keyframes loader {
0% {
-webkit-transform:rotate(0deg);
transform:rotate(0deg);
}
100% {
-webkit-transform:rotate(360deg);
transform:rotate(360deg);
}
}
.z-btn-wrap{
display: flex;
align-items: center;
justify-content: center;
height: 120rpx;
background: #ffffff;
}
.z-btn{
background: #06CAD8;
color: #ffffff;
display: flex;
justify-content: center;
align-items: center;
padding: 24rpx 40rpx;
font-size: 32rpx;
font-weight: 500;
border-radius: 10rpx;
min-width: 400rpx;
}
(3)index.js
import TIM from "tim-wx-sdk";
const {getDatePattern,isJSON} = getApp().require('utils/util');
let DATA_APP = getApp() && getApp().globalData || {};
let DATA_TIM = DATA_APP.TIM || {};
let TIM_MSG = [];
Page({
data: {
colToView: '',
colUserId: '自己的IM userID',
colUserOtherId: '对方的IM userID',
colSendMsg: '',
colPercent: 0,
pageLastLength: 1,
pageNext: '',
pageCompleted: '',
showSendMore: false,
showLoading: false,
showThree: false,
showEnd: false,
arrMsg: [],
arrImg: [],
},
onLoad(options) {
this.TIM_getMsgList();
//订阅初始化获取聊天记录
wx.event.on('conversationInit', () => {
this.TIM_getMsgList();
});
//订阅收到消息
wx.event.on('received', (e) => {
this.TIM_setGlobalMsg(e,'received');
});
},
//im获取消息、打开某个会话时,第一次拉取消息列表
TIM_getMsgList() {
this.onShowLoading();
let param = {
conversationID: 'C2C' + this.data.colUserOtherId,
count: 15,
nextReqMessageID: this.data.pageNext
};
let promise = DATA_TIM.getMessageList(param);
promise.then((imResponse) => {
this.TIM_setGlobalMsg(imResponse, 'load', true);
});
},
//im获取消息、打开某个会话时,第一次拉取消息列表
TIM_getMsgListMore() {
this.onShowLoading();
let param = {
conversationID: 'C2C' + this.data.colUserOtherId,
count: 15,
nextReqMessageID: this.data.pageNext
};
let promise = DATA_TIM.getMessageList(param);
promise.then((imResponse) => {
this.TIM_setGlobalMsg(imResponse, 'load');
});
},
//im创建文本消息
TIM_createMsg() {
let param = {
to: this.data.colUserOtherId,
conversationType: TIM.TYPES.CONV_C2C,
payload: {
text: this.data.colSendMsg
}
};
let message = DATA_TIM.createTextMessage(param);
this.TIM_sendMessageFun(message);
this.onClearInput();
},
//im创建自定义消息
TIM_createMsgCustom(msg) {
let paramText = {
name:'名字',
sex:'男',
age:'27',
weight:'60kg',
height:'171cm',
desc:'长期肥胖,需要减肥',
descTime:'一年',
history:'暂无',
allergy:'无',
type:'describe'
};
let param = {
to: this.data.colUserOtherId,
conversationType: TIM.TYPES.CONV_C2C,
payload: {
data: JSON.stringify(paramText), // 用于标识该消息是骰子类型消息
description: '描述主题', // 获取骰子点数
extension: '描述说明'
}
};
let message = DATA_TIM.createCustomMessage(param);
this.TIM_sendMessageFun(message);
},
// im创建图片- 选择图片
TIM_createPhoto(e) {
let that = this;
let name = e.currentTarget.dataset.name;
if (name === 'album') {
that.TIM_createPhotoNow(name)
} else if (name === 'camera') {
wx.getSetting({
success: function (res) {
if (!res.authSetting['scope.camera']) { // 无权限,跳转设置权限页面
wx.authorize({
scope: 'scope.camera',
success: function () {
that.TIM_createPhotoNow(name)
}
})
} else {
that.TIM_createPhotoNow(name)
}
}
})
}
},
// im创建图片- 创建完成
TIM_createPhotoNow(name) {
let that = this;
let colUserId = this.data.colUserId;
wx.chooseImage({
sourceType: [name],
count: 1,
success: (res) => {
// 在发送之前先push进去一张图片
let messageList = that.data.arrMsg;
let data = {
type: 'TIMImageElem',
send: true,
from: colUserId,
showSendMore: res.tempFilePaths[0]
};
messageList.push(data);
that.setData({
arrMsg: messageList
});
that.onHideSendMore();
that.pageScrollToBottom(true);
// 2. 创建消息实例,接口返回的实例可以上屏
let message = DATA_TIM.createImageMessage({
to: that.data.colUserOtherId, // 消息的接收方,
conversationType: TIM.TYPES.CONV_C2C,
payload: {file: res},
onProgress: (event) => {
event = event || 0;
that.setData({
colPercent: event * 100
})
}
});
that.TIM_sendMessageFun(message,'TIMImageElem')
}
})
},
//im发送-处理
TIM_sendMessageFun(message, type) {
DATA_TIM.sendMessage(message).then((imResponse) => {
// 发送成功
if (type === 'TIMImageElem') {
let messageList = this.data.arrMsg;
messageList.pop();
this.setData({
arrMsg: messageList
})
}
this.TIM_setGlobalMsg(imResponse, 'send');
this.onHideSendMore();
this.onClearInput();
}).catch((imError) => {
console.warn('发送失败:', imError);
})
},
//im处理数据
TIM_setGlobalMsg(imResponse, type, loadFirst) {
console.log('消息列表',imResponse);
if (type === 'send'||type === 'received') {
let data = {};
if(type === 'received'){
data = imResponse.data[0];
// this.setData({
// showThree:false,
// })
}else {
data = imResponse.data.message||{};
}
let arrMsg = this.data.arrMsg;
let arrImg = this.data.arrImg;
if (data.type === 'TIMImageElem') {
arrImg.push(data.payload.imageInfoArray[0].url);
}
if(data.type === 'TIMCustomElem') {
data.dataCustom = isJSON(data.payload.data)? JSON.parse(data.payload.data):{};
}
data.timeFormat = getDatePattern(new Date(data.time * 1000), 'yyyy-MM-dd HH:mm');
arrMsg.push(data);
this.setData({
arrMsg: arrMsg,
arrImg: arrImg,
}, () => {
this.pageScrollToBottom(true)
});
}else {
let data = imResponse.data||{};
let arrData = data.messageList || [];
let arrImg = [];
arrData = arrData.map(x => {
if (x.type === 'TIMImageElem') {
arrImg.push(x.payload.imageInfoArray[0].url);
}
if(x.type === 'TIMCustomElem') {
x.dataCustom = isJSON(x.payload.data)? JSON.parse(x.payload.data):{};
}
x.timeFormat = getDatePattern(new Date(x.time * 1000), 'yyyy-MM-dd HH:mm')
return x
});
arrImg = arrImg.concat(this.data.arrImg);
TIM_MSG = arrData.concat(this.data.arrMsg);// 全局消息列表
this.setData({
'arrMsg': TIM_MSG,
'arrImg': arrImg,
'pageNext': data.nextReqMessageID,// 用于续拉,分页续拉时需传入该字段。
'pageCompleted': data.isCompleted,// 表示是否已经拉完所有消息。
'pageLastLength':arrData.length//用户定位滚动位置
}, () => {
this.onHideLoading();
this.pageScrollToBottom(loadFirst)
});
}
},
//实时更新输入框的数据
onInputMsg(e) {
this.setData({
'colSendMsg': e.detail.value
})
},
onClearInput() {
this.setData({
'colSendMsg': ''
})
},
//显示加载框
onShowLoading() {
this.setData({
'showLoading': true
});
},
//隐藏加载框
onHideLoading() {
this.setData({
'showLoading': false
});
},
// 点更多出现图片和相册
onShowSendMore() {
this.setData({
showSendMore: true
})
},
// 点击屏幕 发消息更多的弹框下去
onHideSendMore() {
this.setData({
showSendMore: false
})
},
// 预览
previewImage(e) {
let url = e.currentTarget.dataset.url;
wx.previewImage({
current: url, // 当前显示图片的http链接
urls: this.data.arrImg
})
},
//滚动到页面底部
pageScrollToBottom(isBottom) {
let index = null;
if (isBottom) {
index = 'msg-' + (this.data.arrMsg.length - 1);
} else {
index = 'msg-' + 0;
}
this.setData({
colToView: index
})
},
//加载更多
onLoadMore() {
if (!this.data.pageCompleted) {
this.TIM_getMsgListMore()
}
},
});
四:资料
- 以上所有文件附上(链接:https://pan.baidu.com/s/1hJkXUfaeoY5Y0O6ceQeLYw 提取码:x4h6 )
- 腾讯云IM官网
- 腾讯云IM技术文档
- 参考博客1
- 参考博客2
五:我的项目部分截图