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

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

现在开始我的第二个功能模块:聊天室,经过和后台同事们的沟通与交流,决定使用腾讯云通信,来实现该功能。(后台接通腾讯云通信,给我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、在界面中展示该表情符列表:
<!-- 表情 -->
      <view class='video-discuss-emotion' id='video-discuss-emotion'>
        <view class='video-emotion-pane'>
          <view wx:for="{{emojiChar}}" wx:key="msg-{{index}}" class='view-pane'>
            <view data-current-key="{{index}}" bindtap='emojiClick'>{{item.emoji}}</view>
          </view>

        </view>
      </view>
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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,362评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,577评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,486评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,852评论 1 317
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,600评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,944评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,944评论 3 447
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,108评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,652评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,385评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,616评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,111评论 5 364
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,798评论 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,205评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,537评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,334评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,570评论 2 379

推荐阅读更多精彩内容

  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,800评论 0 10
  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,853评论 0 15
  • 2017.02.22 可以练习,每当这个时候,脑袋就犯困,我这脑袋真是神奇呀,一说让你做事情,你就犯困,你可不要太...
    Carden阅读 1,366评论 0 1
  • 一、iOS 直播聊天室 Demo 说明 1、源码结构 2、AppDelegate 在 AppDelegate 中初...
    ajiao焦阅读 2,896评论 2 7
  • 月夜下,用脚步丈量我儿时玩耍的每一寸土地。每一户人家,每一片土地,都有深深的回忆。 月光如此皎洁,夜如此静寂,千年...
    小狗快跑嘟嘟阅读 225评论 0 0