备注:公司需要做一个微信小程序,本人属于微信小程序小白,从未做过微信小程序,于是开始了我的学习之路
现在开始我的第二个功能模块:聊天室,经过和后台同事们的沟通与交流,决定使用腾讯云通信,来实现该功能。(后台接通腾讯云通信,给我roomID)
Step1:进入官网查看如何接通SDK,以及如何使用
https://cloud.tencent.com/document/product/269/32941
注意:配置一定要正确,不然后续工作无法继续进行
根据上述的步骤,获取SdkAppId,配置应用,我下载了上述的微信小程序的demo,修改了一系列的配置之后,运行成功,也能成功聊天,然后将一系列工具文件配置到我的项目中,但是随后我发现创建的聊天室类型是 AVChatRoom,而我需要的是 ChatRoom或者 Public类型的,你肯定要问了,聊天室的类型不同在哪里?见下图:
那么接下来,就得改造了。
标红的webim_handler.js是Demo中对webmi_wx.js进行包装之后的工具类,我进行改造的就是它,因为我觉得这样比较简单点,当然,如果童鞋你觉得还能更简便快捷,也欢迎留言。
Step2:通过后台给出的接口,传入用户名nickName,获取相对应的userSig,进入聊天室
// 进入聊天室
entry: function(userSig) {
const {
userInfo
} = this.data;
var self = this;
// 防止两次点击操作间隔太快
var nowTime = new Date();
if (nowTime - this.data.tapTime < 1000) {
return;
}
var identifier = userInfo.nickName;
console.log(identifier);
console.log(userSig);
var url = `../live/live?identifier=${identifier}&userSig=${userSig}&headurl=${userInfo.avatarUrl}`;
wx.navigateTo({
url: url
});
wx.showToast({
title: '登录IM',
icon: 'success',
duration: 1000
})
self.setData({
'tapTime': nowTime
});
},
Step3:进入聊天室,根据获取到的identifier、userSig、headurl以及roomId登录聊天室,进行聊天操作。
1、改造的第一步,修改调用的live.js 文件中的内容:
(1)去掉webimhandler.init里面的avChatRoomId
(2)修改listeners中的接收消息的接听,去掉onBigGroupMsgNotify,修改onMsgNotify
(3)另外根据我的需求,需要在聊天室中展示头像,所以在loginInfo中多了一个传入了一个:'headurl': headurl,仅供参考
//live.js
//获取应用实例
var webim = require('../../utils/webim_wx.js');
var webimhandler = require('../../utils/webim_handler.js');
const CONFIG = require('../config');
global.webim = webim;
var Config = CONFIG.app;
const app = getApp()
Page({
data: {
//聊天室数据
identifier: '', // 当前用户身份标识,必选
userSig: '', // 当前用户签名,必选
nickName: '', // 当前用户昵称,选填
headurl: '', // 当前用户头像,选填
msgs: [],
msgContent: "",
},
/** ==============聊天室开始==================== **/
clearInput: function() {
this.setData({
msgContent: ""
})
},
bindConfirm: function(e) {
console.log('发送');
var that = this;
var content = e.detail.value;
if (!content.replace(/^\s*|\s*$/g, '')) return;
webimhandler.onSendMsg(content, function() {
that.clearInput();
})
},
bindInputfocus: function(e){
console.log('bindInputfocus===',e);
},
bindTap: function() {
webimhandler.sendGroupLoveMsg();
},
receiveMsgs: function(data) {
console.log('receiveMsgs', data);
var msgs = this.data.msgs || [];
msgs.push(data);
this.setData({
msgs: msgs
})
},
initIM: function() {
var that = this;
const {
nickName,
identifier,
userSig,
headurl,
room_id: chatRoomId
} = this.data;
webimhandler.init({
accountMode: 0, //帐号模式,0-表示独立模式,1-表示托管模式(已停用,仅作为演示)
accountType: Config.accountType,
sdkAppID: Config.sdkappid,
// avChatRoomId: avChatRoomId, //默认房间群ID,群类型必须是直播聊天室(AVChatRoom),这个为官方测试ID(托管模式)
selType: webim.SESSION_TYPE.GROUP,
selToID: chatRoomId,
selSess: null //当前聊天会话
});
//当前用户身份
var loginInfo = {
'sdkAppID': Config.sdkappid, //用户所属应用id,必填
'appIDAt3rd': Config.sdkappid, //用户所属应用id,必填
'accountType': Config.accountType, //用户所属应用帐号类型,必填
'identifier': identifier, //当前用户ID,必须是否字符串类型,选填
'identifierNick': nickName || '', //当前用户昵称,选填
'userSig': userSig, //当前用户身份凭证,必须是字符串类型,选填
'headurl': headurl,
};
//监听(多终端同步)群系统消息方法,方法都定义在demo_group_notice.js文件中
var onGroupSystemNotifys = {
"5": webimhandler.onDestoryGroupNotify, //群被解散(全员接收)
"11": webimhandler.onRevokeGroupNotify, //群已被回收(全员接收)
"255": webimhandler.onCustomGroupNotify //用户自定义通知(默认全员接收)
};
//监听连接状态回调变化事件
var onConnNotify = function(resp) {
switch (resp.ErrorCode) {
case webim.CONNECTION_STATUS.ON:
//webim.Log.warn('连接状态正常...');
break;
case webim.CONNECTION_STATUS.OFF:
webim.Log.warn('连接已断开,无法收到新消息,请检查下你的网络是否正常');
break;
default:
webim.Log.error('未知连接状态,status=' + resp.ErrorCode);
break;
}
};
//监听事件
var listeners = {
"onConnNotify": webimhandler.onConnNotify, //选填
// "onBigGroupMsgNotify": function(msg) {
// webimhandler.onBigGroupMsgNotify(msg, function(msgs) {
// that.receiveMsgs(msgs);
// })
// }, //监听新消息(大群)事件,必填
"onMsgNotify": function(msg) {
webimhandler.onMsgNotify(msg, function(msgs) {
that.receiveMsgs(msgs);
})
}, //监听新消息(私聊(包括普通消息和全员推送消息),普通群(非直播聊天室)消息)事件,必填
"onGroupSystemNotifys": webimhandler.onGroupSystemNotifys, //监听(多终端同步)群系统消息事件,必填
"onGroupInfoChangeNotify": webimhandler.onGroupInfoChangeNotify //监听群资料变化事件,选填
};
//其他对象,选填
var options = {
'isAccessFormalEnv': true, //是否访问正式环境,默认访问正式,选填
'isLogOn': true //是否开启控制台打印日志,默认开启,选填
};
webimhandler.sdkLogin(loginInfo, listeners, options, chatRoomId);
},
/** ==============聊天室结束==================== **/
onUnload: function() {
// 登出
webimhandler.logout();
},
})
2、改造的第二步,修改调用的webim_handler.js 文件中的内容:
(1)修改init方法:去掉 avChatRoomId,添加对消息的处理 callback(showMsg(newMsg));
function init(opts) {
accountMode = opts.accountMode;
accountType = opts.accountType;
sdkAppID = opts.sdkAppID;
// avChatRoomId = opts.avChatRoomId;
selType = opts.selType;
selToID = opts.selToID;
}
(2)1 - >修改sdkLogin方法:添加 Tag_Profile_IM_Image,修改头像;2 - >修改GroupIdList:avChatRoomId修改为chatRoomId;3 - >添加createGroup 、applyJoinGroup方法,替换掉createBigGroup 、applyJoinBigGroup方法,区别在于一个是AVChatRoom,一个是普通群(ChatRoom或者Public等);4 - >修改showMsg方法,添加fromAccountHeadurl的赋值以及返回
//sdk登录
function sdkLogin(userInfo, listeners, options, chatRoomId) {
//web sdk 登录
webim.login(userInfo, listeners, options,
function (identifierNick) {
//identifierNick为登录用户昵称(没有设置时,为帐号),无登录态时为空
console.debug(identifierNick);
webim.Log.info('webim登录成功');
loginInfo = userInfo;
setProfilePortrait({
'ProfileItem': [{
"Tag": "Tag_Profile_IM_Nick",
"Value": userInfo.identifierNick
}, {
"Tag": "Tag_Profile_IM_Image",
"Value": userInfo.headurl
}]
}, function () {
var options = {
'GroupIdList': [
// avChatRoomId
chatRoomId
],
'GroupBasePublicInfoFilter': [
'Type',
'Name',
'Introduction',
'Notification',
'FaceUrl',
'CreateTime',
'Owner_Account',
'LastInfoTime',
'LastMsgTime',
'NextMsgSeq',
'MemberNum',
'MaxMemberNum',
'ApplyJoinOption'
]
};
webim.getGroupPublicInfo(
options,
function (resp) {
console.log('getGroupPublicInfo success', resp);
if (resp.GroupInfo.length > 0) {
// applyJoinBigGroup(avChatRoomId);//加入大群
applyJoinGroup(chatRoomId);//加入群
} else {
// //测试代码,先创建群,确保群存在,正常的业务中无需这样处理。
// createBigGroup(avChatRoomId, loginInfo, function () {
// applyJoinBigGroup(avChatRoomId);//加入大群
// });
createGroup(chatRoomId, loginInfo, function () {
applyJoinGroup(chatRoomId);//加入群
});
}
},
function (err) {
console.log('getGroupPublicInfo error', err);
// //测试代码,先创建群,确保群存在,正常的业务中无需这样处理。
// createBigGroup(avChatRoomId, loginInfo, function () {
// applyJoinBigGroup(avChatRoomId);//加入大群
// });
createGroup(chatRoomId, loginInfo, function () {
applyJoinGroup(chatRoomId);//加入群
});
}
);
})
//hideDiscussForm();//隐藏评论表单
initEmotionUL();//初始化表情
},
function (err) {
console.error(err);
wx.showToast({
title: '登录失败,code=' + err.ErrorCode,
icon: 'none',
duration: 2000
})
}
);//
}
//创建普通群
function createGroup(groupId, loginInfo, callback) {
console.log('createGroup', loginInfo)
var options = {
'GroupId': groupId,
'Owner_Account': loginInfo.identifier,
'Type': 'Public', // 房间类型可为ChatRoom
'Name': 'DemoGroup',
'MemberList': [],
"ApplyJoinOption": "FreeAccess" // 申请加群处理方式(选填)
};
webim.createGroup(
options,
function (resp) {
console.info('succ')
callback();
},
function (err) {
console.error(err.ErrorInfo);
callback();
}
);
}
//进入普通群
function applyJoinGroup(groupId) {
var options = {
'GroupId': groupId//群id
};
webim.applyJoinGroup(
options,
function (resp) {
if (resp.JoinedStatus && resp.JoinedStatus == 'JoinedSuccess') {
webim.Log.info('进群成功');
selToID = groupId;
} else {
console.error('进群失败');
}
},
function (err) {
console.error(err.ErrorInfo);
}
);
}
//显示消息(群普通+点赞+提示+红包)
function showMsg(msg) {
var isSelfSend, fromAccount, fromAccountNick, fromAccountHeadurl, sessType, subType;
var ul, li, paneDiv, textDiv, nickNameSpan, contentSpan;
console.log('msg====', msg);
fromAccount = msg.getFromAccount();
if (!fromAccount) {
fromAccount = '';
}
fromAccountNick = msg.getFromAccountNick();
if (!fromAccountNick) {
fromAccountNick = '未知用户';
}
fromAccountHeadurl = msg.fromAccountHeadurl;
//解析消息
//获取会话类型,目前只支持群聊
//webim.SESSION_TYPE.GROUP-群聊,
//webim.SESSION_TYPE.C2C-私聊,
sessType = msg.getSession().type();
//获取消息子类型
//会话类型为群聊时,子类型为:webim.GROUP_MSG_SUB_TYPE
//会话类型为私聊时,子类型为:webim.C2C_MSG_SUB_TYPE
subType = msg.getSubType();
isSelfSend = msg.getIsSend();//消息是否为自己发的
var content = "";
switch (subType) {
case webim.GROUP_MSG_SUB_TYPE.COMMON://群普通消息
content = convertMsgtoHtml(msg);
break;
case webim.GROUP_MSG_SUB_TYPE.REDPACKET://群红包消息
content = "[群红包消息]" + convertMsgtoHtml(msg);
break;
case webim.GROUP_MSG_SUB_TYPE.LOVEMSG://群点赞消息
//业务自己可以增加逻辑,比如展示点赞动画效果
content = "[群点赞消息]" + convertMsgtoHtml(msg);
//展示点赞动画
showLoveMsgAnimation();
break;
case webim.GROUP_MSG_SUB_TYPE.TIP://群提示消息
content = "[群提示消息]" + convertMsgtoHtml(msg);
break;
}
return {
fromAccountHeadurl: fromAccountHeadurl,
fromAccountNick: fromAccountNick,
content: content
}
}
(3)修改onMsgNotify方法:去掉 handlderMsg(newMsg);,添加对消息的处理 callback(showMsg(newMsg));
//监听新消息(私聊(包括普通消息、全员推送消息),普通群(非直播聊天室)消息)事件
//newMsgList 为新消息数组,结构为[Msg]
function onMsgNotify(newMsgList, callback) {
var newMsg;
for (var j in newMsgList) {//遍历新消息
newMsg = newMsgList[j];
// handlderMsg(newMsg);//处理新消息
//显示收到的消息
callback(showMsg(newMsg));
}
}
Step4:最后,发现无法使用demo中的表情面板,但是键盘中自带的表情符又能在消息中正常展示,且是作为文本类型的消息被接收,所以和同事商量了出来,直接使用表情符号,插入文本中,作为文本类型的消息发送出去
1、收集表情符,做成表情符列表,以下内容仅供参考,可自行编辑:
emojiChar: [{
num: "01",
emoji: ""
},
{
num: "02",
emoji: ""
},
{
num: "03",
emoji: ""
},
{
num: "04",
emoji: ""
},
{
num: "05",
emoji: ""
},
{
num: "06",
emoji: ""
},
{
num: "07",
emoji: ""
},
{
num: "08",
emoji: ""
},
{
num: "09",
emoji: ""
},
{
num: "10",
emoji: ""
},
{
num: "11",
emoji: ""
},
{
num: "12",
emoji: ""
},
{
num: "13",
emoji: ""
},
{
num: "14",
emoji: ""
},
{
num: "15",
emoji: ""
},
{
num: "16",
emoji: ""
},
{
num: "17",
emoji: ""
},
{
num: "18",
emoji: ""
},
{
num: "19",
emoji: ""
},
{
num: "20",
emoji: ""
},
{
num: "21",
emoji: ""
},
{
num: "22",
emoji: ""
},
{
num: "23",
emoji: ""
},
{
num: "24",
emoji: ""
},
{
num: "25",
emoji: ""
},
{
num: "26",
emoji: ""
},
{
num: "27",
emoji: ""
},
{
num: "28",
emoji: ""
},
{
num: "29",
emoji: ""
},
{
num: "30",
emoji: ""
},
{
num: "31",
emoji: ""
},
{
num: "32",
emoji: ""
},
{
num: "33",
emoji: ""
},
{
num: "34",
emoji: ""
},
{
num: "35",
emoji: ""
},
{
num: "36",
emoji: "✊"
},
{
num: "37",
emoji: ""
},
{
num: "38",
emoji: ""
},
{
num: "39",
emoji: ""
},
{
num: "40",
emoji: ""
},
{
num: "41",
emoji: ""
},
{
num: "42",
emoji: ""
},
],
2、在界面中展示该表情符列表:
{{item.emoji}}
2、在点击事件emojiClick中将表情符加入输入框内容的操作:
注意:在此处,原本想做的操作是:将表情符精准插入输入框的内容里面,但是试过多种方法,都无法精准获取input 的光标位置,所以只能将表情符加入到原有的文本内容之后。比如:你好吗?变成:你好吗?,无论输入表情前光标位置在哪里,都只能放到最后。如果有童鞋能精准获取光标位置,请一定要告知我,谢谢!
bindinput方法只能在有输入的情况下获取cursor,如果只是移动光标,不进行其他操作,无法获取cursor,所以不精准;经试验bindInputfocus方法,不能得到cursor
bindInputfocus: function(e){
console.log('bindInputfocus===',e);
},
bindinput(event){
console.log('bindinput==event=', event);
let pos = event.detail.cursor
if (pos != -1) {
this.setData({
currentFocusIndex: pos
});
}
console.log('bindinput0000==event=', pos);
this.setData({
msgContent: event.detail.value
});
// 直接返回对象,可以对输入进行过滤处理,同时可以控制光标的位置
return {
value: event.detail.value,
cursor: pos
}
},
//点击表情
emojiClick(e){
const currentKey = e.currentTarget.dataset && e.currentTarget.dataset.currentKey;
const { emojiChar, msgContent, currentFocusIndex = -1 } = this.data;
// console.log('emojiClick==msgContent==11=', msgContent);
// if (currentFocusIndex !== -1){
// const tempMsgLeft = msgContent.substring(0,currentFocusIndex);
// const tempMsgRight = msgContent.substring(currentFocusIndex);
// console.log('emojiClick==tempMsgLeft===', tempMsgLeft);
// console.log('emojiClick==tempMsgRight===', tempMsgRight);
this.setData({
msgContent: msgContent + emojiChar[currentKey].emoji
});
// }
},
另外,我还在研究如何传图片,目前想要实现的是base64的方式,但是现在还没完成,有待继续研究,有已经完成的童鞋希望能给与意见,欢迎留言!!!!
文章摘自:
https://cloud.tencent.com/document/product/269/32941
https://developers.weixin.qq.com/miniprogram/dev/component/input.html