小程序学习之路二:聊天室

备注:公司需要做一个微信小程序,本人属于微信小程序小白,从未做过微信小程序,于是开始了我的学习之路

现在开始我的第二个功能模块:聊天室,经过和后台同事们的沟通与交流,决定使用腾讯云通信,来实现该功能。(后台接通腾讯云通信,给我roomID)


Step1:进入官网查看如何接通SDK,以及如何使用

https://cloud.tencent.com/document/product/269/32941

注意:配置一定要正确,不然后续工作无法继续进行

根据上述的步骤,获取SdkAppId,配置应用,我下载了上述的微信小程序的demo,修改了一系列的配置之后,运行成功,也能成功聊天,然后将一系列工具文件配置到我的项目中,但是随后我发现创建的聊天室类型是 AVChatRoom,而我需要的是 ChatRoom或者 Public类型的,你肯定要问了,聊天室的类型不同在哪里?见下图:
image.png
那么接下来,就得改造了。
image.png
标红的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

你可能感兴趣的:(小程序学习之路二:聊天室)