文章目录
项目场景:代码示例:一、聊天功能二、发送消息后滚动到底部三、历史记录查询及下拉加载更多功能实现四、微信小程序即时聊天功能其他注意事项五、本文参考文章项目场景:
微信小程序中实现websocket,即时聊天功能
核心包含以下内容
1.聊天功能实现
2.发送消息后滚动到底部
3.历史记录查询及下拉加载更多功能实现
代码示例:
wxml
<!--pages/wechat2/wechat2.wxml--><view class="chat-header"><view class="header-image-box"><image class="header-image" src="{{receivebaseInfo.avatar}}"></image></view><view><view class="chat-name">{{receivebaseInfo.nickname}}</view><view class="chat-company">{{pany_name}} - {{receivebaseInfo.department_name}}</view></view></view><view class='news'><view class="historycon"><scroll-view scroll-y="true" scroll-into-view="{{scrollid}}" scroll-with-animation = "{{true}}" style="height:{{scrollHeight}}" class="history"refresher-enabled="true"bindrefresherrefresh="refresh"refresher-triggered="{{triggered}}"><!-- 历史记录部分start --><view wx:if="{{historyList.length > 0}}"><view class="historyText">历史消息</view><block wx:for="{{historyList}}" wx:key="index"><!--此处为other --><view wx:if="{{item.type==1}}" id="historyscrollid{{index}}"><view><text class='chat-time' style="display:none;">{{item.date}}</text></view><view class='other-record'><image class='other-head-img' src='{{receivebaseInfo.avatar}}'></image><view class='other-record-content-triangle'></view><view class='other-record-content'>{{item.content_msg}}</view></view></view><!--此处为结尾 --><!--此处为own --><view id="historyscrollid{{index}}" wx:else><view><text class='chat-time' style="display:none;">{{item.date}}</text></view><view class='own-record'><view class='own-record-content'>{{item.content_msg}}</view><view class='own-record-content-triangle'></view><image class='own-head-img' src='{{sendAvatar}}'></image></view></view><!-- own结尾 --></block><view class="historyText">以上为历史消息</view></view><!-- 历史记录部分end --><block wx:for="{{newsList}}" wx:key="index"><!--此处为other --><view wx:if="{{item.type==1}}" id="scrollid{{index}}"><view><text class='chat-time' style="display:none;">{{item.date}}</text></view><view class='other-record'><image class='other-head-img' src='{{receivebaseInfo.avatar}}'></image><view class='other-record-content-triangle'></view><view class='other-record-content'>{{item.message}}</view></view></view><!--此处为结尾 --><!--此处为own --><view id="scrollid{{index}}" wx:else><view><text class='chat-time' style="display:none;">{{item.date}}</text></view><view class='own-record'><view class='own-record-content'>{{item.message}}</view><view class='own-record-content-triangle'></view><image class='own-head-img' src='{{sendAvatar}}'></image></view></view><!-- own结尾 --></block></scroll-view></view></view><view class="sendmessage"><view class="send-message"><input class="chat-input" type="text" bindinput="bindChange" confirm-type="done" value='{{input}}' cursor-spacing="16px" hold-keyboard="{{true}}" placeholder="" /><image class="chat-emotion" src="../../static/img/chat-emotion.svg" bindtap="emotionChange"></image><button class="btn" bindtap='send'>发送</button></view><view class="emotions" wx:if="{{emotionVisible}}"><view class="emotions-item" wx:for="{{connectemoji}}" wx:key="index" bindtap="addemotion" data-index="{{index}}">{{item}}</view></view></view>
**说明:**结构主要包括头部聊天方的信息部分,历史记录部分,即时聊天内容部分,发送消息部分
wxss
/* pages/wechat2/wechat2.wxss */page {background-color: #f3f3f4; } /* 新增样式 */.chat-header {display: flex;align-items: center;justify-content: flex-start;height: 88px;padding: 0 12px;background-color: #fff;border-radius: 0px 0px 10px 10px;}.header-image-box {width: 64px;height: 64px;border-radius: 50%;margin-right: 12px;}.header-image {width: 100%;height: 100%;border-radius: 50%;}.chat-name {color: #333;font-size: 16px;font-weight: 700;}.chat-company {font-size: 14px;color: rgba(81, 81, 81, 100);}.tab {padding: 20rpx 20rpx 40rpx 50rpx; height: 20%; background-color: white; } .tab .tent {font-size: 33rpx; margin-bottom: 30rpx; } .jia_img{height: 80rpx; width: 90rpx; } .new_imgtent{height: 180rpx; width: 190rpx; } .tab .fabu {font-size: 33rpx; margin-top: 30rpx; margin-bottom: 30rpx; } .xiahuaxia {width: 80%; text-align: center; margin: 0 auto; position: relative; top: 60rpx; } .chat-time {text-align: center; padding: 5rpx 20rpx 5rpx 20rpx; width: 200rpx; font-size: 26rpx; background-color: #e6e6e6; } .new_top_txt {width: 50%; position: relative; top: 38rpx; text-align: center; margin: 0 auto; font-size: 30rpx; color: #787878; background-color: #f7f7f7; } /* 聊天内容 */ .news {margin-top: 30px; text-align: center; margin-bottom: 98px; } .img_null {height: 60rpx; } .l {height: 5rpx; width: 20%; margin-top: 30rpx; color: #000; } /* 聊天 */ .my_right {float: right; position: relative; right: 40rpx; } .you_left {float: left; position: relative; left: 5rpx; } .new_img {width: 100rpx; height: 100rpx; border-radius: 50%; } .sanjiao {top: 20rpx; position: relative; width: 0px; height: 0px; border-width: 10px; border-style: solid; } .my {border-color: transparent transparent transparent #95d4ff; } .you {border-color: transparent #95d4ff transparent transparent; } .sendmessage {/* display: flex;align-items: center;flex-direction: row; */width: 100%; min-height: 60px;position: fixed; bottom: 0px; padding: 0 16px;background-color: rgba(242, 242, 242, 100); box-shadow: 0px -1px 5px 1px rgba(57, 57, 57, 0.1);} .send-message {display: flex;align-items: center;padding: 16px;}.sendmessage input {height: 80rpx; background-color: white; line-height: 80rpx; font-size: 28rpx; padding-left: 20rpx; } .sendmessage button {width: 52px !important; height: 32px; line-height: 32px;background: #169171 !important; color: #fff !important; font-size: 14px !important;text-align: center;border: 0 !important;padding: 0 !important;margin: 0 !important;} .historycon {height: 90%; /* background-color: pink; */width: 100%; flex-direction: column; display: flex; /* margin-top: 100rpx; */border-top: 0px; } .hei{margin-top: 50px; height: 20rpx; } .history {/* height: 300px; */margin-top: 30rpx; margin: 20rpx; font-size: 28rpx; line-height: 80rpx; word-break: break-all; } .chat-input{width: 60%;height: 40px;border: 0;border-radius: 8px;margin-left: 5rpx;}.back-icon{margin-top: 25rpx;margin-left: 25rpx; width:40rpx;height:40rpx;}.other-record-content{background-color: #fff;width: 180px; border-radius: 7px; padding: 0 20px;text-align: left;margin: 6px 0;}.other-record{display: flex;justify-content:flex-start;}.other-head-img{width:70rpx;height:70rpx;border-radius: 50%;margin: 10rpx 10rpx 10rpx 10rpx;}.other-record-content-triangle{width: 0; height: 0; border-top: 10rpx solid transparent; border-right: 15rpx solid #fff; border-bottom: 10rpx solid transparent;margin-top: 36rpx; }.own-record{display: flex;justify-content:flex-end;padding-right:30rpx; }.own-record-content{background-color: #209072;width: 180px; border-radius: 8px; padding: 0 20px;color: #fff;text-align: left;margin: 6px 0;}.own-record-content-triangle {width: 0; height: 0; /* border-top: 20rpx solid transparent; border-left: 40rpx solid #F0F0F0; border-bottom: 20rpx solid transparent; */border-top: 10rpx solid transparent; border-left: 15rpx solid #209072; border-bottom: 10rpx solid transparent; margin-top: 36rpx; }.own-head-img{width:70rpx;height:70rpx;border-radius: 50%;margin: 10rpx 10rpx 10rpx 10rpx;}::-webkit-scrollbar{width: 0;height: 0;color: transparent;}.chat-emotion {width: 28px;height: 28px;margin: 0 12px;}.emotions {display: flex;align-items: flex-start;justify-content: flex-start;width: 200px;height: 36px;margin: 6px;}.emotions-item {width: 24px;height: 24px;margin: 0 8px;}.historyText {color: #ccc;}
js
var utils = require("../../utils/util.js")const app = getApp()const api = require('../../utils/request.js'); //相对路径Page({/*** 页面的初始数据*/data: {receivebaseInfo:{},sendAvatar:'',newsList:[{date: ".10.19",message:'哈喽,好久不见',type: 0},{date: ".10.20",message:'是呀,好久不见',type: 1},{date: ".10.20",message:'是呀,好久不见',type: 1},],//消息列表historyList:[],input:null,openid:null,connectemoji: ["😘","😡","😔","😄","❤"],emoji_list: ['emoji1i1', 'emoji2i2', 'emoji3i3', 'emoji4i4', 'emoji5i5'],emotionVisible: false,inputShowed: false,scrollTop: 0,inputBottom: '0px',receiveMemberId:null,sendMemberId:null,scrollid:'scrollid',scrollHeight:'300px',// 下拉刷新triggered:true,// 历史记录当前页pageNo: 1,},/*** 生命周期函数--监听页面加载*/onLoad: function (options) {var receiveMemberId = options.receiveMemberIdvar sendMemberId = app.globalData.open_idvar sendAvatar = app.globalData.sendAvatarvar _this = this;_this.setData({receiveMemberId,sendMemberId,sendAvatar})console.log(app.globalData.sendAvatar,'hahha')// 获取内存中的数据this.getStorageBaseInfo()// 设置滚动区域的高度this.setScrollHeight()// 获取历史记录 this.getHistory()// 初始化websocketthis.initWebSocket()// 页面进入滚动到底部this.scrollBottom()},/*** 生命周期函数--监听页面初次渲染完成*/onReady: function () {},// websocket初始化initWebSocket: function(){var _this = this;var {receiveMemberId, sendMemberId} = this.data//建立连接wx.connectSocket({url: `ws://10.200.18.18:1818/zxxt/${sendMemberId}/${receiveMemberId}`,//本地success: function () {console.log('websocket连接成功~')},fail: function () {console.log('websocket连接失败~')},})//连接成功wx.onSocketOpen(function () {console.log('onSocketOpen','连接成功,真正的成功');})// 接收服务器的消息事件wx.onSocketMessage(function(res){// 接收到的消息{date,message,type} type类型为 1 是对方的消息 为 0 是自己的消息var list = [];list = _this.data.newsList;var _data = JSON.parse(res.data);list.push(_data);console.log(list)_this.setData({newsList:list})_this.scrollBottom()},)// 监听连接关闭wx.onSocketClose(function(){console.log('监听 WebSocket 连接关闭事件')})},// 获取历史记录getHistory: function(){var {receiveMemberId, sendMemberId,pageNo} = this.datavar params = {receiveMemberId,sendMemberId,pageNo,pageSize:5,}api.get("/zxxt/chat/msg/list", params, (res) => {if (res.code == 'success') {// var historyList = res.data.datavar historyList = [...res.data.data,...this.data.historyList]if (historyList && historyList.length > 0) {historyList.forEach(item => {if (item.send_member_id == sendMemberId) {item.type = 0}else {item.type = 1}});this.setData({historyList})console.log(this.data.historyList,'历史记录数据')}else {// 判断是否是第一次进入查看历史记录:是(不显示弹框,不是则显示弹框)if(this.data.pageNo > 1) {wx.showToast({title: "没有更多历史记录了",icon: 'none',duration: 2000})}}} else {if (res.message) {wx.showToast({title: res.message,icon: 'none',duration: 2000})}}}, (res) => {if (res.message) {wx.showToast({title: res.message,icon: 'none',duration: 2000})}})},// 滚动到底部scrollBottom:function() {var {newsList} = this.datavar scrollid = `scrollid${newsList.length - 1}`this.setData({scrollid})},// 设置滚动区域的高度setScrollHeight:function(){const client = wx.getSystemInfoSync().windowHeight // 获取当前窗口的高度var scrollHeight = (client - 236) + 'px'this.setData({scrollHeight})},// 获取内存中聊天列表的用户信息getStorageBaseInfo: function(){//获取存储信息wx.getStorage({key: 'receivebaseInfo',success: (res)=>{this.setData({receivebaseInfo:res.data})}})},// 自定义下拉刷新refresh: function(){// 下拉的实际操作var pageNo = this.data.pageNo + 1this.setData({pageNo})if (this.timer) {clearTimeout(this.timer)}this.timer = setTimeout(()=>{this.setData({triggered:false})this.getHistory()},2000)},/*** 生命周期函数--监听页面显示*/onShow: function () {},/*** 生命周期函数--监听页面隐藏*/onHide: function () {},/*** 生命周期函数--监听页面卸载*/onUnload: function () {},/*** 页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh: function () {},/*** 页面上拉触底事件的处理函数*/onReachBottom: function () {},/*** 用户点击右上角分享*/onShareAppMessage: function () {},send :function(){var _this = this;if(_this.data.input){wx.sendSocketMessage({data: _this.data.input,success: (res) =>{console.log(res)},fail: (err)=>{console.log('sendSocketMessage','失败')}})var list = [];list = this.data.newsList;var temp = {'message': _this.data.input, 'date': utils.formatTime(new Date()), type: 0 };list.push(temp);this.setData({newsList:list,input:null})this.scrollBottom()// 表情选择隐藏this.setData({emotionVisible:false,})}// this.bottom()const client = wx.getSystemInfoSync().windowHeight // 获取当前窗口的高度console.log(client,'shurugaodu')},bindChange:function(res){this.setData({input: res.detail.value,})},back:function(){wx.closeSocket();console.log('连接断开');},emotionChange:function(){this.setData({emotionVisible:!this.data.emotionVisible})},addemotion:function(e){console.log(e.currentTarget.dataset.index,"点了设默默")let {connectemoji,input} = this.dataif (input) {input = input + connectemoji[e.currentTarget.dataset.index];}else {input = connectemoji[e.currentTarget.dataset.index]}console.log(input,'输入框额值')this.setData({input})},// 公共聚焦方法,方法比较笨,但是过度效果平滑流畅bottom: function() {var that = this;// 获取元素的高度let query = wx.createSelectorQuery();query.select('.news').boundingClientRect(rect => {//获取到元素let scrollTop = rect.height;this.setData({scrollTop})}).exec();console.log(this.data.scrollTop,'hahah')wx.pageScrollTo({// scrollTop: this.data.scrollTop + 30,scrollTop: 10000,// duration: 0})},})
一、聊天功能
核心api
1.wx.connectSocket
2.wx.onSocketOpen
3.wx.onSocketMessage
4.wx.onSocketClose
5.链接微信开发文档机票
二、发送消息后滚动到底部
核心方法
1.scroll-view 的使用(wxml)
<scroll-view scroll-y="true" scroll-into-view="{{scrollid}}" scroll-with-animation = "{{true}}" style="height:{{scrollHeight}}" class="history"refresher-enabled="true"bindrefresherrefresh="refresh"refresher-triggered="{{triggered}}"></scroll-view>
2.scrollBottom方法(js)
// 滚动到底部scrollBottom:function() {var {newsList} = this.datavar scrollid = `scrollid${newsList.length - 1}`this.setData({scrollid})},
三、历史记录查询及下拉加载更多功能实现
核心部分
1.scroll-view 的使用(wxml)
<scroll-view scroll-y="true" scroll-into-view="{{scrollid}}" scroll-with-animation = "{{true}}" style="height:{{scrollHeight}}" class="history"refresher-enabled="true"bindrefresherrefresh="refresh"refresher-triggered="{{triggered}}"></scroll-view>
2.getHistory方法(js)
// 获取历史记录getHistory: function(){var {receiveMemberId, sendMemberId,pageNo} = this.datavar params = {receiveMemberId,sendMemberId,pageNo,pageSize:5,}api.get("/zxxt/chat/msg/list", params, (res) => {if (res.code == 'success') {// var historyList = res.data.datavar historyList = [...res.data.data,...this.data.historyList]if (historyList && historyList.length > 0) {historyList.forEach(item => {if (item.send_member_id == sendMemberId) {item.type = 0}else {item.type = 1}});this.setData({historyList})console.log(this.data.historyList,'历史记录数据')}else {// 判断是否是第一次进入查看历史记录:是(不显示弹框,不是则显示弹框)if(this.data.pageNo > 1) {wx.showToast({title: "没有更多历史记录了",icon: 'none',duration: 2000})}}} else {if (res.message) {wx.showToast({title: res.message,icon: 'none',duration: 2000})}}}, (res) => {if (res.message) {wx.showToast({title: res.message,icon: 'none',duration: 2000})}})},
注:此方法可写在初始化websocket的回掉函数中
3.scroll-view开发文档及配置机票
四、微信小程序即时聊天功能其他注意事项
1.ws://10.200.157.18:8005/ 与wss的区别
2.微信小程序input使用hold-keyboard保持键盘不收起配置 hold-keyboard="{{true}}"
3.键盘遮挡input及textarea配置 cursor-spacing=“16px”
<input class="chat-input" type="text" bindinput="bindChange" confirm-type="done" value='{{input}}' cursor-spacing="16px" hold-keyboard="{{true}}" placeholder="" />
五、本文参考文章
文章参考机票
包含前端后代码很有参考价值
相关git推荐
前后端代码机票
websocket在线 测试工具机票