> 文章列表 > 微信小程序+wx.connectSocket客服问答

微信小程序+wx.connectSocket客服问答

微信小程序+wx.connectSocket客服问答

项目需求,记录一下:

1.要求websocket实时返回会话结果

我项目这边是后端一次返回一个字,–finish–结束,所以实现方法是每获取到数据时就setData一次,直到获取到的数据为finish,停止setData
后端返回结果如图
微信小程序+wx.connectSocket客服问答

2.会话自动回滚到底部

用wx.createSelectorQuery()获取页面上的节点信息,可获得相对于显示区域的上下左右边界坐标,详情可点开链接查看
注意:每次发出问题,或者接受结果时都要重新计算节点信息

3.会话缓存(我这里用到的是wx.setStorageSync())

微信小程序+wx.connectSocket客服问答
话不多说,上代码
wxml

<view >
<!-- isHe是为了首次进入页面时,要不要计算节点信息,如果没有缓存默认高度撑起来;有缓存,计算页面节点信息,获取滚动高度 -->
<view id="idView" style="height:{{isHe?'90vh':'auto'}};padding-bottom: 15vh;overflow: scroll;"><block wx:key wx:for='{{msgList}}' wx:for-index="index"><!-- 单个消息1 客服发出(左) --><view wx:if='{{item.speaker=="server"}}' class="servers" id='msg-{{index}}' style='display: flex; padding: 2vw 11vw 2vw 2vw;'><view style='width: 11vw; height: 11vw;'><!-- 机器人图片 --><image style='width: 11vw; height: 11vw; border-radius: 10rpx;' src='../../../assets/images/member/robot.png'></image></view><view style='width: 4vw; height: 11vw; margin-left: 0.5vw; display: flex; align-items: center; z-index: 9;'><image style='width: 4vw;' src='../../../assets/images/member/left.png' mode='widthFix'></image></view><block><!-- 发出消息等待返回结果时,三点加载动画 --><view wx:if="{{isDisable && item.content==''}}" user-select='{{true}}' class='leftMsg loadView' space="nbsp" decode="{{true}}"><view class="dot1"> </view><view class="dot2"></view><view class="dot3"></view></view><text user-select='{{true}}' class='leftMsg' space="nbsp" decode="{{true}}">{{item.content}}</text></block></view><!-- 单个消息2 用户发出(右) --><view wx:else id='msg-{{index}}' style='display: flex; justify-content: flex-end; padding: 2vw 2vw 2vw 11vw;'><view class='rightMsg'>{{item.content}}</view><view style='width: 4vw; height: 11vw; margin-right: 0.5vw; display: flex; align-items: center; z-index: 9;'><!-- 左右箭头,见下图 --><image style='width: 4vw;' src='../../../assets/images/member/right.png' mode='widthFix'></image></view><view style='width: 11vw; height: 11vw;'><image style='width: 11vw; height: 11vw; border-radius: 10rpx;' src='{{cusHeadIcon}}'></image></view></view></block>
</view><view class='inputRoom'><input data-value="{{inputVal}}" disabled='{{isDisable}}' data-type="1" type="text" placeholder="请输入你的问题" confirm-type="send" bindconfirm='sendClick' value='{{inputVal}}' bindinput="ontext"></input><image wx:if="{{!isDisable}}" data-type="2" bindtap='sendClick' class="sendIcon" src='../../../assets/images/member/send.png' mode='widthFix'></image><image wx:else class="sendIcon" src='../../../assets/images/member/send.png' mode='widthFix'></image>
</view>
</view>

微信小程序+wx.connectSocket客服问答
用到的api
wx.connectSocket()创建websocket连接
wx.onSocketOpen()监听websocket连接打开事件
wx.sendSocketMessage()发送数据,需要先 wx.connectSocket,并在 wx.onSocketOpen 回调之后才能发送
wx.onSocketMessage()监听websocket接收到服务器的消息事件
wx.createSelectorQuery()获取节点信息,如节点位置,文本内容等
wx.pageScrollTo()将页面滚动到目标位置,支持选择器和滚动距离两种方式定位
wx.closeSocket()关闭websocket连接
wx.onSocketClose()监听websocket连接关闭事件
js

const commonMixin = require('../../../utils/commonMixin')const app = getApp();
var inputVal = '';
var msgList = [];
var windowWidth = wx.getSystemInfoSync().windowWidth;
var windowHeight = wx.getSystemInfoSync().windowHeight;
var keyHeight = 0;let socketOpen = false;
let socketMsgQueue = [];
/*** 初始化数据*/
function initData(that) {inputVal = '';msgList = [{speaker: 'server',contentType: 'text',content: '你好,我是人工智能助手,请问有什么可以帮你?'}, ]that.setData({msgList,inputVal})
}function sendSocketMessage(msg) {console.log(socketOpen,'socketOpen',msg);if (socketOpen) {wx.sendSocketMessage({data: msg})} else {socketMsgQueue.push(msg)}
}Page(Object.assign({/*** 页面的初始数据*/data: {scrollTop: 0,isHe: false,text:'',isDisable:false,  // 发送消息等待回话时,input框禁用inputBottom: 0},/*** 生命周期函数--监听页面加载*/onLoad: function (options) {initData(this);this.setData({cusHeadIcon: app.globalData.userInfo.avatar || app.globalData.userInfo.avatarUrl,});},/*** 生命周期函数--监听页面显示*/onShow: function () {let that = this;let list =wx.getStorageSync('memberList')console.log(list,'list');// 判断是否有缓存,有缓存时,计算页面节点信息,设置滚动距离if (list?.length>0) { // 有缓存that.setData({msgList:JSON.parse(list)})wx.createSelectorQuery().select('#idView').boundingClientRect(function (rect) {// 使页面滚动到底部wx.pageScrollTo({scrollTop: rect.height+rect.bottom   // 滚动距离})that.setData({scrollTop: rect.height+rect.bottom,isHe: false});}).exec()}else{  //没有缓存,默认高度是90vhwx.setStorageSync('memberList', JSON.stringify(this.data.msgList))that.setData({isHe: true,})}wx.connectSocket({url: 'wss://' + 连接地址 success(){console.log('连接成功')}})wx.onSocketOpen((res) => {socketOpen = trueconsole.log("打开socket");socketMsgQueue = []wx.onSocketMessage((result) => {result.data = result.data.replace(" ", "&nbsp;");var str = result.data.indexOf("--finish--") != -1  // 判断返回的数据中是否包含‘--finish--’wx.createSelectorQuery().select('#idView').boundingClientRect(function (rect) {// 使页面滚动到底部wx.pageScrollTo({scrollTop: rect.height+rect.bottom})that.setData({scrollTop: rect.height+rect.bottom,isHe: false});}).exec()if (!!result.data) {result.data=str?result.data.replace('--finish--',''):result.dataconsole.log(that.data.msgList,'-');that.data.msgList[that.data.msgList.length - 1].content = that.data.msgList[that.data.msgList.length - 1].content + result.datathat.setData({msgList:that.data.msgList})if (str) {// 包含‘finish’结束字符,将返回结果存入缓存 let list =wx.getStorageSync('memberList')?JSON.parse(wx.getStorageSync('memberList')):[]list.push({speaker: 'server',contentType: 'text',content: that.data.msgList[that.data.msgList.length - 1].content})wx.setStorageSync('memberList',JSON.stringify(list))}}if(str){that.setData({isDisable:false,})}})})},onHide: function () {console.log('onhide');wx.closeSocket()wx.onSocketClose((result) => {console.log("socket关闭成功");wx.showToast({icon: 'none',title: '会话关闭成功',duration: 500})})},onUnload:function(){console.log('onUnload',);wx.closeSocket()wx.onSocketClose((result) => {console.log("socket关闭成功");})},/*** 页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh: function () {},/*** 页面上拉触底事件的处理函数*/onReachBottom: function () {},ontext:function(e){this.setData({text:e.detail.value})},sendClick:function(e){ // 发送问题计算页面信息,滚动距离let that = thiswx.createSelectorQuery().select('#idView').boundingClientRect(function (rect) {// 使页面滚动到底部wx.pageScrollTo({scrollTop: rect.height+rect.bottom})that.setData({height: 'auto',scrollTop: rect.height+rect.bottom});}).exec()that.setData({isDisable:true})sendSocketMessage(that.data.text)  //发送问题msgList.push({speaker: 'customer',contentType: 'text',content: that.data.text})let list =wx.getStorageSync('memberList')?JSON.parse(wx.getStorageSync('memberList')):[]list.push({speaker: 'customer',contentType: 'text',content: that.data.text})// 将发送的问题存入缓存wx.setStorageSync('memberList', JSON.stringify(list))msgList.push({speaker: 'server',contentType: 'text',content: ''})inputVal = '';// 这里list.push一个空内容,是为了让三个点加载出现,相当于一个占位符list.push({speaker: 'server',contentType: 'text',content: ''})that.setData({msgList:list,text:'',inputVal});}
}, commonMixin))

wxss

page {background-color: #f1f1f1;}
.inputRoom{height: 10vh;display: flex;align-items: center;z-index: 999;background: #f1f1f1;position: fixed;bottom: 0;width: 100%;
}input {width: 76vw;height: 9.33vw;background-color: #fff;border-radius: 40rpx;margin-left: 2vw;padding: 0 3vw;font-size: 28rpx;color: #444;}.leftMsg {font-size: 35rpx;color: #444;line-height: 7vw;padding: 2vw 2.5vw;background-color: #fff;margin-left: -1.6vw;border-radius: 10rpx;z-index: 10;word-break: break-all;}.rightMsg {font-size: 35rpx;color: #444;line-height: 7vw;padding: 2vw 2.5vw;background-color: #96EB6A;margin-right: -1.6vw;border-radius: 10rpx;z-index: 10;}input{height: 12vw !important;margin-bottom: 3vh;}.servers:nth-last-of-type(2){margin-bottom: 5vw;}.servers:nth-last-of-type(2)>.leftMsg{padding-bottom: 5vw;}.sendIcon{width: 7vw;margin-left: 3.2vw;margin-bottom: 3vh}.loadView{display: flex;padding-top: 4vw;}.dot1, .dot2, .dot3 {background: #fff;width: 10rpx;height: 10rpx;border-radius: 50%;margin: 10rpx;
}.dot1 {animation: jump 1.6s -0.32s linear infinite;background: #ccc;
}
.dot2 {animation: jump 1.6s -0.16s linear infinite;background: #ccc;
}
.dot3 {animation: jump 1.6s linear infinite;background: #ccc;
}@keyframes jump {0%, 80%, 100% {-webkit-transform: scale(0);transform: scale(0);} 40% {-webkit-transform: scale(2.0);transform: scale(2.0);}
}

至此就结束啦!有不足之处欢迎指出~