uniapp——实现聊天室功能——技能提升

这里写目录标题

  • 效果图
  • 聊天室功能
  • 代码——`html`部分
  • 代码——`js`部分
  • 代码——`其他`部分

首先声明一点:下面的内容是从一个uniapp的程序中摘录的,并非本人所写,先做记录,以免后续遇到相似需求抓耳挠腮。

效果图

在这里插入图片描述

聊天室功能

发送图片 相机 发红包系列 聊天 发送表情
代码中还包含发送语音,但是测试发现,该功能不太成熟,而且页面上并未提供发送语音的入口。

代码——html部分

<template><view><view class="content" @touchstart="hideDrawer"><scroll-view class="msg-list" :class="popupLayerClass" scroll-y="true":scroll-with-animation="scrollAnimation" :scroll-top="scrollTop" :scroll-into-view="scrollToView"@scrolltoupper="loadHistory" upper-threshold="50"><!-- 加载历史数据waitingUI --><view class="loading"><view class="spinner"><view class="rect1"></view><view class="rect2"></view><view class="rect3"></view><view class="rect4"></view><view class="rect5"></view></view></view><view class="row" v-for="(row,index) in msgList" :key="index" :id="'msg'+row.msg.id"><!-- 系统消息 --><block v-if="row.type=='system'"><view class="system"><!-- 文字消息 --><view v-if="row.msg.type=='text'" class="text">{{row.msg.content.text}}</view><!-- 领取红包消息 --><view v-if="row.msg.type=='redEnvelope'" class="red-envelope"><image src="/static/chat/red-envelope-chat.png"></image>{{row.msg.content.text}}</view></view></block><!-- 用户消息 --><block v-if="row.type=='user'"><!-- 自己发出的消息 --><view class="my" v-if="row.msg.userinfo.uid==myuid"><!---消息 --><view class="left"><!-- 文字消息 --><view v-if="row.msg.type=='text'" class="bubble"><rich-text :nodes="row.msg.content.text"></rich-text></view><!-- 语言消息 --><view v-if="row.msg.type=='voice'" class="bubble voice" @tap="playVoice(row.msg)":class="playMsgid == row.msg.id?'play':''"><view class="length">{{row.msg.content.length}}</view><view class="icon my-voice"></view></view><!-- 图片消息 --><view v-if="row.msg.type=='img'" class="bubble img" @tap="showPic(row.msg)"><image :src="row.msg.content.url":style="{'width': row.msg.content.w+'px','height': row.msg.content.h+'px'}"></image></view><!-- 红包 --><view v-if="row.msg.type=='redEnvelope'" class="bubble red-envelope"@tap="openRedEnvelope(row.msg,index)"><image src="/static/chat/red-envelope.png"></image><view class="tis"><!-- 点击开红包 --></view><view class="blessing">{{row.msg.content.blessing}}</view></view></view><!---头像 --><view class="right"><image :src="row.msg.userinfo.face"></image></view></view><!-- 别人发出的消息 --><view class="other" v-if="row.msg.userinfo.uid!=myuid"><!---头像 --><view class="left"><image :src="row.msg.userinfo.face"></image></view><!---用户名称-时间-消息 --><view class="right"><view class="username"><view class="name">{{row.msg.userinfo.username}}</view><view class="time">{{row.msg.time}}</view></view><!-- 文字消息 --><view v-if="row.msg.type=='text'" class="bubble"><rich-text :nodes="row.msg.content.text"></rich-text></view><!-- 语音消息 --><view v-if="row.msg.type=='voice'" class="bubble voice" @tap="playVoice(row.msg)":class="playMsgid == row.msg.id?'play':''"><view class="icon other-voice"></view><view class="length">{{row.msg.content.length}}</view></view><!-- 图片消息 --><view v-if="row.msg.type=='img'" class="bubble img" @tap="showPic(row.msg)"><image :src="row.msg.content.url":style="{'width': row.msg.content.w+'px','height': row.msg.content.h+'px'}"></image></view><!-- 红包 --><view v-if="row.msg.type=='redEnvelope'" class="bubble red-envelope"@tap="openRedEnvelope(row.msg,index)"><image src="/static/chat/red-envelope.png"></image><view class="tis"><!-- 点击开红包 --></view><view class="blessing">{{row.msg.content.blessing}}</view></view></view></view></block></view></scroll-view></view><!-- 抽屉栏 --><view class="popup-layer" :class="popupLayerClass" @touchmove.stop.prevent="discard"><!-- 表情 --><swiper class="emoji-swiper" :class="{hidden:hideEmoji}" indicator-dots="true" duration="150"><swiper-item v-for="(page,pid) in emojiList" :key="pid"><view v-for="(em,eid) in page" :key="eid" @tap="addEmoji(em)"><!-- https://zhoukaiwen.com/img/icon/emojj1/1.png --><image mode="widthFix" :src="'https://zhoukaiwen.com/img/icon/emojj1/'+em.url"></image></view></swiper-item></swiper><!-- 更多功能 相册-拍照-红包 --><view class="more-layer" :class="{hidden:hideMore}"><view class="list"><view class="box" @tap="chooseImage"><view class="icon tupian2"></view></view><view class="box" @tap="camera"><view class="icon paizhao"></view></view><view class="box" @tap="handRedEnvelopes"><view class="icon hongbao"></view></view></view></view></view><!-- 底部输入栏 --><view class="input-box cu-bar tabbar" :class="popupLayerClass" @touchmove.stop.prevent="discard"><!-- H5下不能录音,输入栏布局改动一下 --><!-- #ifndef H5 --><view class="voice"><view class="icon" :class="isVoice?'jianpan':'yuyin'" @tap="switchVoice"></view></view><!-- #endif --><!-- #ifdef H5 --><view class="more" @tap="showMore"><view class="icon add"></view></view><!-- #endif --><view class="textbox"><view class="voice-mode" :class="[isVoice?'':'hidden',recording?'recording':'']"@touchstart="voiceBegin" @touchmove.stop.prevent="voiceIng" @touchend="voiceEnd"@touchcancel="voiceCancel">{{voiceTis}}</view><view class="text-mode" :class="isVoice?'hidden':''"><view class="box"><textarea auto-height="true" v-model="textMsg" @focus="textareaFocus" /></view><view class="em" @tap="chooseEmoji"><view class="icon biaoqing"></view></view></view></view><!-- #ifndef H5 --><view class="more" @tap="showMore"><view class="icon add"></view></view><!-- #endif --><view class="send" :class="isVoice?'hidden':''" @tap="sendText"><view class="btn">发送</view></view></view><!-- 录音UI效果 --><view class="record" :class="recording?'':'hidden'"><view class="ing" :class="willStop?'hidden':''"><view class="icon luyin2"></view></view><view class="cancel" :class="willStop?'':'hidden'"><view class="icon chehui"></view></view><view class="tis" :class="willStop?'change':''">{{recordTis}}</view></view><!-- 红包弹窗 --><view class="windows" :class="windowsState"><!-- 遮罩层 --><view class="mask" @touchmove.stop.prevent="discard" @tap="closeRedEnvelope"></view><view class="layer" @touchmove.stop.prevent="discard"><view class="open-redenvelope"><view class="top"><view class="close-btn"><view class="icon close" @tap="closeRedEnvelope"></view></view><image src="https://zhoukaiwen.com/img/qdpz/face/face_1.jpg"></image></view><view class="from">来自{{redenvelopeData.from}}</view><view class="blessing">{{redenvelopeData.blessing}}</view><view class="money">{{redenvelopeData.money}}</view><view class="showDetails" @tap="toDetails(redenvelopeData.rid)">查看领取详情 <view class="icon to"></view></view></view></view></view></view>
</template>

代码——js部分

<script>export default {data() {return {//文字消息textMsg: '',//消息列表isHistoryLoading: false,scrollAnimation: false,scrollTop: 0,scrollToView: '',msgList: [],msgImgList: [],myuid: 0,//录音相关参数// #ifndef H5//H5不能录音RECORDER: uni.getRecorderManager(),// #endifisVoice: false,voiceTis: '按住 说话',recordTis: "手指上滑 取消发送",recording: false,willStop: false,initPoint: {identifier: 0,Y: 0},recordTimer: null,recordLength: 0,//播放语音相关参数AUDIO: uni.createInnerAudioContext(),playMsgid: null,VoiceTimer: null,// 抽屉参数popupLayerClass: '',// more参数hideMore: true,//表情定义hideEmoji: true,emojiList: [[{"url": "1.png",alt: "[微笑]"}, {"url": "2.png",alt: "[生气]"}, {"url": "3.png",alt: "[坏笑]"}, {"url": "4.png",alt: "[难受]"}, {"url": "5.png",alt: "[困]"}, {"url": "6.png",alt: "[偷看]"}, {"url": "7.png",alt: "[难过]"}, {"url": "8.png",alt: "[斜眼]"}, {"url": "9.png",alt: "[委屈]"}, {"url": "10.png",alt: "[害羞]"}, {"url": "11.png",alt: "[裂开]"}, {"url": "12.png",alt: "[偷笑]"}, {"url": "13.png",alt: "[痛苦]"}, {"url": "14.png",alt: "[白眼]"}, {"url": "15.png",alt: "[丑]"}, {"url": "16.png",alt: "[哇哇哭]"}, {"url": "17.png",alt: "[笑嘻嘻]"}, {"url": "18.png",alt: "[盯着你]"}, {"url": "19.png",alt: "[啊哈]"}, {"url": "20.png",alt: "[吃瓜]"}, {"url": "21.png",alt: "[哦吼]"}, {"url": "22.png",alt: "[哭死]"}, {"url": "23.png",alt: "[打脸]"}, {"url": "24.png",alt: "[斗鸡眼]"}],[{"url": "25.png",alt: "[发呆]"}, {"url": "26.png",alt: "[憨笑]"}, {"url": "27.png",alt: "[无语]"}, {"url": "28.png",alt: "[鸡贼]"}, {"url": "29.png",alt: "[大无语]"}, {"url": "30.png",alt: "[哭吐了]"}, {"url": "31.png",alt: "[呲牙笑]"}, {"url": "32.png",alt: "[奸笑]"}, {"url": "33.png",alt: "[啊啊啊]"}, {"url": "34.png",alt: "[哈嘿]"}, {"url": "35.png",alt: "[惊讶]"}, {"url": "36.png",alt: "[指你]"}, {"url": "37.png",alt: "[可爱型]"}, {"url": "38.png",alt: "[快哭了]"}, {"url": "39.png",alt: "[抠鼻屎]"}, {"url": "40.png",alt: "[酷酷]"}, {"url": "41.png",alt: "[笑汗]"}, {"url": "42.png",alt: "[算命]"}, {"url": "43.png",alt: "[红脸坏笑]"}, {"url": "44.png",alt: "[委屈死了]"}, {"url": "45.png",alt: "[爆炸]"}, {"url": "46.png",alt: "[吐了]"}, {"url": "47.png",alt: "[么么哒]"}, {"url": "48.png",alt: "[吐血]"}],[{"url": "49.png",alt: "[面无表情]"}, {"url": "50.png",alt: "[捂嘴吐]"}, {"url": "51.png",alt: "[斜眼看]"}, {"url": "52.png",alt: "[花痴]"}, {"url": "53.png",alt: "[被打]"}, {"url": "54.png",alt: "[瞌睡]"}, {"url": "55.png",alt: "[冥想]"}, {"url": "56.png",alt: "[俏皮]"}, {"url": "57.png",alt: "[戳手委屈]"}, {"url": "58.png",alt: "[端庄]"}, {"url": "59.png",alt: "[emmm]"}, {"url": "60.png",alt: "[欢呼]"}, {"url": "61.png",alt: "[笑哭了]"}, {"url": "62.png",alt: "[抱抱]"}, {"url": "63.png",alt: "[闭眼笑]"}, {"url": "64.png",alt: "[捂嘴微笑]"}, {"url": "65.png",alt: "[笑哭2]"}, {"url": "66.png",alt: "[笑嘻嘻]"}, {"url": "67.png",alt: "[笑露齿]"}, {"url": "68.png",alt: "[阴脸笑]"}, {"url": "69.png",alt: "[问号脸]"}, {"url": "70.png",alt: "[拜拜]"}, {"url": "71.png",alt: "[难受2]"}, {"url": "72.png",alt: "[傻笑2]"}],[{"url": "73.png",alt: "[爆炸2]"}, {"url": "74.png",alt: "[二哈]"}, {"url": "75.png",alt: "[二哈吐舌]"}, {"url": "76.png",alt: "[狗狗笑哭]"}, {"url": "77.png",alt: "[狗狗绿帽]"}, {"url": "78.png",alt: "[狗狗张嘴]"}, {"url": "79.png",alt: "[狗狗绿扇]"}, {"url": "80.png",alt: "[狗狗]"}, {"url": "81.png",alt: "[猫咪]"}, {"url": "82.png",alt: "[牛啊]"}, {"url": "83.png",alt: "[爱心]"}, {"url": "84.png",alt: "[心裂开]"}, {"url": "85.png",alt: "[玫瑰花]"}, {"url": "86.png",alt: "[枯萎]"}, {"url": "87.png",alt: "[棒]"}, {"url": "88.png",alt: "[差]"}, {"url": "89.png",alt: "[红药]"}, {"url": "90.png",alt: "[绿药]"}, {"url": "91.png",alt: "[抱拳]"}, {"url": "92.png",alt: "[ok]"}, {"url": "93.png",alt: "[pk]"}, {"url": "94.png",alt: "[绿帽子]"}, {"url": "95.png",alt: "[菜刀]"}]],//表情图片图床名称 ,由于我上传的第三方图床名称会有改变,所以有此数据来做对应,您实际应用中应该不需要onlineEmoji: {"1.png": "1.png","2.png": "2.png","3.png": "3.png","4.png": "4.png","5.png": "5.png","6.png": "6.png","7.png": "7.png","8.png": "8.png","9.png": "9.png","10.png": "10.png","11.png": "11.png","12.png": "12.png","13.png": "13.png","14.png": "14.png","15.png": "15.png","16.png": "16.png","17.png": "17.png","18.png": "18.png","19.png": "19.png","20.png": "20.png","21.png": "21.png","22.png": "22.png","23.png": "23.png","24.png": "24.png","25.png": "25.png","26.png": "26.png","27.png": "27.png","28.png": "28.png","29.png": "29.png","30.png": "30.png","31.png": "31.png","32.png": "32.png","33.png": "33.png","34.png": "34.png","35.png": "35.png","36.png": "36.png","37.png": "37.png","38.png": "38.png","39.png": "39.png","40.png": "40.png","41.png": "41.png","42.png": "42.png","43.png": "43.png","44.png": "44.png","45.png": "45.png","46.png": "46.png","47.png": "47.png","48.png": "48.png","49.png": "49.png","50.png": "50.png","51.png": "51.png","52.png": "52.png","53.png": "53.png","54.png": "54.png","55.png": "55.png","56.png": "56.png","57.png": "57.png","58.png": "58.png","59.png": "59.png","60.png": "60.png","61.png": "61.png","62.png": "62.png","63.png": "63.png","64.png": "64.png","65.png": "65.png","66.png": "66.png","67.png": "67.png","68.png": "68.png","69.png": "69.png","70.png": "70.png","71.png": "71.png","72.png": "72.png","73.png": "73.png","74.png": "74.png","75.png": "75.png","76.png": "76.png","77.png": "77.png","78.png": "78.png","79.png": "79.png","80.png": "80.png","81.png": "81.png","82.png": "82.png","83.png": "83.png","84.png": "84.png","85.png": "85.png","86.png": "86.png","87.png": "87.png","88.png": "88.png","89.png": "89.png","90.png": "90.png","91.png": "91.png","92.png": "92.png","93.png": "93","94.png": "94.png","95.png": "95.png"},//红包相关参数windowsState: '',redenvelopeData: {rid: null, //红包IDfrom: null,face: null,blessing: null,money: null}};},onLoad(option) {this.getMsgList();//语音自然播放结束this.AUDIO.onEnded((res) => {this.playMsgid = null;});// #ifndef H5//录音开始事件this.RECORDER.onStart((e) => {this.recordBegin(e);})//录音结束事件this.RECORDER.onStop((e) => {this.recordEnd(e);})// #endif},onShow() {this.scrollTop = 9999999;//模板借由本地缓存实现发红包效果,实际应用中请不要使用此方法。//uni.getStorage({key: 'redEnvelopeData',success: (res) => {console.log(res.data);let nowDate = new Date();let lastid = this.msgList[this.msgList.length - 1].msg.id;lastid++;let row = {type: "user",msg: {id: lastid,type: "redEnvelope",time: nowDate.getHours() + ":" + nowDate.getMinutes(),userinfo: {uid: 0,username: "大黑哥",face: "https://zhoukaiwen.com/img/kevinLogo.png"},content: {blessing: res.data.blessing,rid: Math.floor(Math.random() * 1000 + 1),isReceived: false}}};this.screenMsg(row);uni.removeStorage({key: 'redEnvelopeData'});}});},methods: {// 接受消息(筛选处理)screenMsg(msg) {//从长连接处转发给这个方法,进行筛选处理if (msg.type == 'system') {// 系统消息switch (msg.msg.type) {case 'text':this.addSystemTextMsg(msg);break;case 'redEnvelope':this.addSystemRedEnvelopeMsg(msg);break;}} else if (msg.type == 'user') {// 用户消息switch (msg.msg.type) {case 'text':this.addTextMsg(msg);break;case 'voice':this.addVoiceMsg(msg);break;case 'img':this.addImgMsg(msg);break;case 'redEnvelope':this.addRedEnvelopeMsg(msg);break;}console.log('用户消息');//非自己的消息震动if (msg.msg.userinfo.uid != this.myuid) {console.log('振动');uni.vibrateLong();}}this.$nextTick(function() {// 滚动到底this.scrollToView = 'msg' + msg.msg.id});},//触发滑动到顶部(加载历史信息记录)loadHistory(e) {if (this.isHistoryLoading) {return;}this.isHistoryLoading = true; //参数作为进入请求标识,防止重复请求this.scrollAnimation = false; //关闭滑动动画let Viewid = this.msgList[0].msg.id; //记住第一个信息ID//本地模拟请求历史记录效果setTimeout(() => {// 消息列表let list = [{type: "user",msg: {id: 1,type: "text",time: "12:56",userinfo: {uid: 0,username: "大黑哥",face: "https://zhoukaiwen.com/img/kevinLogo.png"},content: {text: "web前端开发该怎么学习?"}}},{type: "user",msg: {id: 2,type: "text",time: "12:57",userinfo: {uid: 1,username: "售后客服008",face: "https://zhoukaiwen.com/img/qdpz/face/face_2.jpg"},content: {text: "按照基本路线,从html、css、js三大基础开始,然后ajax、vue进阶学习,最后学习小程序、node、react。"}}},{type: "user",msg: {id: 3,type: "voice",time: "12:59",userinfo: {uid: 1,username: "售后客服008",face: "https://zhoukaiwen.com/img/qdpz/face/face_2.jpg"},content: {url: "/static/voice/1.mp3",length: "00:06"}}},{type: "user",msg: {id: 4,type: "voice",time: "13:05",userinfo: {uid: 0,username: "大黑哥",face: "https://zhoukaiwen.com/img/kevinLogo.png"},content: {url: "/static/voice/2.mp3",length: "00:06"}}},]// 获取消息中的图片,并处理显示尺寸for (let i = 0; i < list.length; i++) {if (list[i].type == 'user' && list[i].msg.type == "img") {list[i].msg.content = this.setPicSize(list[i].msg.content);this.msgImgList.unshift(list[i].msg.content.url);}list[i].msg.id = Math.floor(Math.random() * 1000 + 1);this.msgList.unshift(list[i]);}//这段代码很重要,不然每次加载历史数据都会跳到顶部this.$nextTick(function() {this.scrollToView = 'msg' + Viewid; //跳转上次的第一行信息位置this.$nextTick(function() {this.scrollAnimation = true; //恢复滚动动画});});this.isHistoryLoading = false;}, 1000)},// 加载初始页面消息getMsgList() {// 消息列表let list = [{type: "system",msg: {id: 0,type: "text",content: {text: "欢迎进入Kevin聊天室"}}},{type: "user",msg: {id: 1,type: "text",time: "12:56",userinfo: {uid: 0,username: "大黑哥",face: "https://zhoukaiwen.com/img/kevinLogo.png"},content: {text: "web前端开发该怎么学习?"}}},{type: "user",msg: {id: 2,type: "text",time: "12:57",userinfo: {uid: 1,username: "售后客服008",face: "https://zhoukaiwen.com/img/qdpz/face/face_2.jpg"},content: {text: "按照基本路线,从html、css、js三大基础开始,然后ajax、vue进阶学习,最后学习小程序、node、react。"}}},{type: "user",msg: {id: 3,type: "voice",time: "12:59",userinfo: {uid: 1,username: "售后客服008",face: "https://zhoukaiwen.com/img/qdpz/face/face_2.jpg"},content: {url: "/static/voice/1.mp3",length: "00:06"}}},{type: "user",msg: {id: 4,type: "voice",time: "13:05",userinfo: {uid: 0,username: "大黑哥",face: "https://zhoukaiwen.com/img/kevinLogo.png"},content: {url: "/static/voice/2.mp3",length: "00:06"}}},{type: "user",msg: {id: 5,type: "img",time: "13:05",userinfo: {uid: 0,username: "大黑哥",face: "https://zhoukaiwen.com/img/kevinLogo.png"},content: {url: "https://zhoukaiwen.com/img/Design/logo/psketch3.png",w: 200,h: 200}}},{type: "user",msg: {id: 6,type: "img",time: "12:59",userinfo: {uid: 1,username: "售后客服008",face: "https://zhoukaiwen.com/img/qdpz/face/face_2.jpg"},content: {url: "https://zhoukaiwen.com/img/Design/pc/ybss_jt.png",w: 1920,h: 1080}}},{type: "system",msg: {id: 7,type: "text",content: {text: "欢迎进入Kevin聊天室"}}},{type: "system",msg: {id: 9,type: "redEnvelope",content: {text: "售后客服008领取了你的红包"}}},{type: "user",msg: {id: 10,type: "redEnvelope",time: "12:56",userinfo: {uid: 0,username: "大黑哥",face: "https://zhoukaiwen.com/img/kevinLogo.png"},content: {blessing: "恭喜发财,大吉大利,万事如意",rid: 0,isReceived: false}}},{type: "user",msg: {id: 11,type: "redEnvelope",time: "12:56",userinfo: {uid: 1,username: "售后客服008",face: "https://zhoukaiwen.com/img/qdpz/face/face_2.jpg"},content: {blessing: "恭喜发财",rid: 1,isReceived: false}}},]// 获取消息中的图片,并处理显示尺寸for (let i = 0; i < list.length; i++) {if (list[i].type == 'user' && list[i].msg.type == "img") {list[i].msg.content = this.setPicSize(list[i].msg.content);this.msgImgList.push(list[i].msg.content.url);}}this.msgList = list;// 滚动到底部this.$nextTick(function() {//进入页面滚动到底部this.scrollTop = 9999;this.$nextTick(function() {this.scrollAnimation = true;});});},//处理图片尺寸,如果不处理宽高,新进入页面加载图片时候会闪setPicSize(content) {// 让图片最长边等于设置的最大长度,短边等比例缩小,图片控件真实改变,区别于aspectFit方式。let maxW = uni.upx2px(350); //350是定义消息图片最大宽度let maxH = uni.upx2px(350); //350是定义消息图片最大高度if (content.w > maxW || content.h > maxH) {let scale = content.w / content.h;content.w = scale > 1 ? maxW : maxH * scale;content.h = scale > 1 ? maxW / scale : maxH;}return content;},//更多功能(点击+弹出) showMore() {this.isVoice = false;this.hideEmoji = true;if (this.hideMore) {this.hideMore = false;this.openDrawer();} else {this.hideDrawer();}},// 打开抽屉openDrawer() {this.popupLayerClass = 'showLayer';},// 隐藏抽屉hideDrawer() {this.popupLayerClass = '';setTimeout(() => {this.hideMore = true;this.hideEmoji = true;}, 150);},// 选择图片发送chooseImage() {this.getImage('album');},//拍照发送camera() {this.getImage('camera');},//发红包handRedEnvelopes() {uni.navigateTo({url: 'hand/hand'});this.hideDrawer();},//选照片 or 拍照getImage(type) {this.hideDrawer();uni.chooseImage({sourceType: [type],sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有success: (res) => {for (let i = 0; i < res.tempFilePaths.length; i++) {uni.getImageInfo({src: res.tempFilePaths[i],success: (image) => {console.log(image.width);console.log(image.height);let msg = {url: res.tempFilePaths[i],w: image.width,h: image.height};this.sendMsg(msg, 'img');}});}}});},// 选择表情chooseEmoji() {this.hideMore = true;if (this.hideEmoji) {this.hideEmoji = false;this.openDrawer();} else {this.hideDrawer();}},//添加表情addEmoji(em) {this.textMsg += em.alt;},//获取焦点,如果不是选表情ing,则关闭抽屉textareaFocus() {if (this.popupLayerClass == 'showLayer' && this.hideMore == false) {this.hideDrawer();}},// 发送文字消息sendText() {this.hideDrawer(); //隐藏抽屉if (!this.textMsg) {return;}let content = this.replaceEmoji(this.textMsg);let msg = {text: content}this.sendMsg(msg, 'text');this.textMsg = ''; //清空输入框},//替换表情符号为图片replaceEmoji(str) {let replacedStr = str.replace(/\[([^(\]|\[)]*)\]/g, (item, index) => {console.log("str: " + str);console.log("index: " + index);console.log("item: " + item);for (let i = 0; i < this.emojiList.length; i++) {let row = this.emojiList[i];for (let j = 0; j < row.length; j++) {let EM = row[j];if (EM.alt == item) {//在线表情路径,图文混排必须使用网络路径,请上传一份表情到你的服务器后再替换此路径 //比如你上传服务器后,你的100.gif路径为https://www.xxx.com/emoji/100.gif 则替换onlinePath填写为https://www.xxx.com/emoji/let onlinePath = 'https://zhoukaiwen.com/img/icon/emojj1/'let imgstr = '<img width="32rpx" src="' + onlinePath + this.onlineEmoji[EM.url] +'">';console.log("imgstr: " + imgstr);return imgstr;}}}});return '<div style="display: flex;align-items: center;word-wrap:break-word;">' + replacedStr + '</div>';},// 发送消息sendMsg(content, type) {//实际应用中,此处应该提交长连接,模板仅做本地处理。var nowDate = new Date();let lastid = this.msgList[this.msgList.length - 1].msg.id;lastid++;let msg = {type: 'user',msg: {id: lastid,time: nowDate.getHours() + ":" + nowDate.getMinutes(),type: type,userinfo: {uid: 0,username: "大黑哥",face: "https://zhoukaiwen.com/img/kevinLogo.png"},content: content}}// 发送消息this.screenMsg(msg);// 定时器模拟对方回复,三秒setTimeout(() => {lastid = this.msgList[this.msgList.length - 1].msg.id;lastid++;msg = {type: 'user',msg: {id: lastid,time: nowDate.getHours() + ":" + nowDate.getMinutes(),type: type,userinfo: {uid: 1,username: "售后客服008",face: "https://zhoukaiwen.com/img/qdpz/face/face_2.jpg"},content: content}}// 本地模拟发送消息this.screenMsg(msg);}, 3000)},// 添加文字消息到列表addTextMsg(msg) {this.msgList.push(msg);},// 添加语音消息到列表addVoiceMsg(msg) {this.msgList.push(msg);},// 添加图片消息到列表addImgMsg(msg) {msg.msg.content = this.setPicSize(msg.msg.content);this.msgImgList.push(msg.msg.content.url);this.msgList.push(msg);},addRedEnvelopeMsg(msg) {this.msgList.push(msg);},// 添加系统文字消息到列表addSystemTextMsg(msg) {this.msgList.push(msg);},// 添加系统红包消息到列表addSystemRedEnvelopeMsg(msg) {this.msgList.push(msg);},// 打开红包openRedEnvelope(msg, index) {let rid = msg.content.rid;uni.showLoading({title: '加载中...'});console.log("index: " + index);//模拟请求服务器效果setTimeout(() => {//加载数据if (rid == 0) {this.redenvelopeData = {rid: 0, //红包IDfrom: "大黑哥",face: "https://zhoukaiwen.com/img/qdpz/face/face.jpg",blessing: "恭喜发财,大吉大利",money: "已领完"}} else {this.redenvelopeData = {rid: 1, //红包IDfrom: "售后客服008",face: "https://zhoukaiwen.com/img/qdpz/face/face_2.jpg",blessing: "恭喜发财",money: "0.01"}if (!msg.content.isReceived) {// {type:"system",msg:{id:8,type:"redEnvelope",content:{text:"你领取了售后客服008的红包"}}},this.sendSystemMsg({text: "你领取了" + (msg.userinfo.uid == this.myuid ? "自己" : msg.userinfo.username) + "的红包"}, 'redEnvelope');console.log("this.msgList[index]: " + JSON.stringify(this.msgList[index]));this.msgList[index].msg.content.isReceived = true;}}uni.hideLoading();this.windowsState = 'show';}, 200)},// 关闭红包弹窗closeRedEnvelope() {this.windowsState = 'hide';setTimeout(() => {this.windowsState = '';}, 200)},sendSystemMsg(content, type) {let lastid = this.msgList[this.msgList.length - 1].msg.id;lastid++;let row = {type: "system",msg: {id: lastid,type: type,content: content}};this.screenMsg(row)},//领取详情toDetails(rid) {uni.navigateTo({url: 'details/details?rid=' + rid})},// 预览图片showPic(msg) {uni.previewImage({indicator: "none",current: msg.content.url,urls: this.msgImgList});},// 播放语音playVoice(msg) {this.playMsgid = msg.id;this.AUDIO.src = msg.content.url;this.$nextTick(function() {this.AUDIO.play();});},// 录音开始voiceBegin(e) {if (e.touches.length > 1) {return;}this.initPoint.Y = e.touches[0].clientY;this.initPoint.identifier = e.touches[0].identifier;this.RECORDER.start({format: "mp3"}); //录音开始,},//录音开始UI效果recordBegin(e) {this.recording = true;this.voiceTis = '松开 结束';this.recordLength = 0;this.recordTimer = setInterval(() => {this.recordLength++;}, 1000)},// 录音被打断voiceCancel() {this.recording = false;this.voiceTis = '按住 说话';this.recordTis = '手指上滑 取消发送'this.willStop = true; //不发送录音this.RECORDER.stop(); //录音结束},// 录音中(判断是否触发上滑取消发送)voiceIng(e) {if (!this.recording) {return;}let touche = e.touches[0];//上滑一个导航栏的高度触发上滑取消发送if (this.initPoint.Y - touche.clientY >= uni.upx2px(100)) {this.willStop = true;this.recordTis = '松开手指 取消发送'} else {this.willStop = false;this.recordTis = '手指上滑 取消发送'}},// 结束录音voiceEnd(e) {if (!this.recording) {return;}this.recording = false;this.voiceTis = '按住 说话';this.recordTis = '手指上滑 取消发送'this.RECORDER.stop(); //录音结束},//录音结束(回调文件)recordEnd(e) {clearInterval(this.recordTimer);if (!this.willStop) {console.log("e: " + JSON.stringify(e));let msg = {length: 0,url: e.tempFilePath}let min = parseInt(this.recordLength / 60);let sec = this.recordLength % 60;min = min < 10 ? '0' + min : min;sec = sec < 10 ? '0' + sec : sec;msg.length = min + ':' + sec;this.sendMsg(msg, 'voice');} else {console.log('取消发送录音');}this.willStop = false;},// 切换语音/文字输入switchVoice() {this.hideDrawer();this.isVoice = this.isVoice ? false : true;},discard() {return;}}}
</script>

代码——其他部分

其他部分代码包含:图标+css+红包系列等。由于内容过多,暂不提供,如有需要,可以评论区留言,我会发送到指定邮箱。

完成!!!多多积累,多多收获!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/136000.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【WFA】【Enhanced open】CT_OWE_DHgroup_STA_NoAssociation-AllGroupsRejected_10338_1

测试报告如下: Fail的关键log: 当连接到ap失败时,驱动程序将尝试连接到ap。如果ap仅支持Group 20,并且sta支持Group 19、20。sta将首先尝试Group 19,ap将通过状态代码77拒绝它。然后驱动程序将尝试连接Group 19的ap,仍然达到最大重试次数。那么sta将尝试第Group 20 。 …

Docker入门,Docker是什么?有什么用?该怎么用?

目录 1. 项目部署时的复杂性&#xff1f; 2. Docker是如何解决依赖兼容问题的&#xff1f; 3. 众多Linux操作系统发行版的区别 4. Docker 是如何实现跨系统运行的&#xff1f; 5. Docker与虚拟机的差别 6. 镜像(Image)与容器(Container) 7. DockerHub 8. Docker 架构 …

Matlab图像处理-强度分层法

强度分层法 强度分层技术是最简单的伪彩色图像处理方法之一。 如果将一幅图像被描述为空间坐标(x,y) 的强度函数f(x,y) &#xff0c;则分层的方法可以看作是将一些平面平行于图像坐标平面(x,y) &#xff0c;然后将每个平面在相交区域切割图像函数。下图展示了使用平面将图像函…

时序预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元时间序列预测

时序预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元时间序列预测 目录 时序预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元时间序列预测效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元时间序列预测。…

项目--苍穹外卖

1.| constant | 存放相关常量类 | | context | 存放上下文类 | | enumeration | 项目的枚举类存储 | | exception | 存放自定义异常类 | | json | 处理json转换的类 | | properties | 存放SpringBoot相关的配置属性类 | | result | 返回结果类的封装 | | utils | 常用工具类 | …

Linux工具(一)

前言&#xff1a;Linux是一个开源的操作系统&#xff0c;它拥有庞大而活跃的开发社区&#xff0c;为用户提供了丰富多样的工具和应用程序。这些工具不仅适用于系统管理员和开发人员&#xff0c;也适用于普通用户&#xff0c;可以帮助他们完成各种任务&#xff0c;从简单的文件管…

宝塔面板日志和缓存占用磁盘空间很大,如何清理?

服务器使用的宝塔面板&#xff0c;最近发现服务器的“系统盘”快爆满了&#xff0c;点面板上日志管理都要收费&#xff0c;我也不是很懂服务器的运维&#xff0c;使用ai进行询问&#xff0c;得到了解决&#xff1a; /var/log 日志目录 运行下面的命令查找是哪些目录占用空间很…

嵌入式Linux驱动开发(I2C专题)(七)

使用GPIO操作I2C设备_IMX6ULL 参考资料&#xff1a; Linux文档 Linux-5.4\Documentation\devicetree\bindings\i2c\i2c-gpio.yamlLinux-4.9.88\Documentation\devicetree\bindings\i2c\i2c-gpio.txt Linux驱动源码 Linux-5.4\drivers\i2c\busses\i2c-gpio.cLinux-4.9.88\driv…

【SpringMVC】文件上传与下载、JREBEL使用

目录 一、引言 二、文件的上传 1、单文件上传 1.1、数据表准备 1.2、添加依赖 1.3、配置文件 1.4、编写表单 1.5、编写controller层 2、多文件上传 2.1、编写form表单 2.2、编写controller层 2.3、测试 三、文件下载 四、JREBEL使用 1、下载注册 2、离线设置 一…

Java增强for循环(学习笔记)

Java增强for循环 主要用于数组或者集合的增强型for循环。 格式&#xff1a; for(声明语句&#xff1a;表达式){ 代码句子 } 声明语句&#xff1a;声明新的局部变量&#xff0c;该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块&#xff0c;其值与此时数组元…

Python 变量作用域

视频版教程 Python3零基础7天入门实战视频教程 在程序中定义一个变量时&#xff0c;这个变量是有作用范围的&#xff0c;变量的作用范围被称为它的作用域。根据定义变量的位置&#xff0c;变量分为两种。 局部变量。在函数中定义的变量&#xff0c;包括参数&#xff0c;都被称…

王道考研操作系统

王道考研操作系统 计算机系统概述操作系统的概念操作系统的特征操作系统的发展历程操作系统内核中断和异常![在这里插入图片描述](https://img-blog.csdnimg.cn/162452b4c60144e0bd500e180127c447.png)系统调用操作系统结构虚拟机错题 进程与线程进程控制进程通信线程和多线程模…

jvm中对象创建、内存布局以及访问定位

对象创建 Java语言层面&#xff0c;创建对象通常&#xff08;例外&#xff1a;复制、反序列化&#xff09;仅仅是一个new关键字即可&#xff0c;而在虚拟机中&#xff0c;对象&#xff08;限于普通Java对象&#xff0c;不包括数组和Class对象等&#xff09;的创建又是怎样一个过…

【直播预约中】 腾讯大数据 x StarRocks|构建新一代实时湖仓

随着信息时代的兴起&#xff0c;数据已成为推动业务决策和创新的核心要素&#xff1b;结构化、半结构化等多种类型的数据呈现爆炸式增长&#xff0c;如何高效处理和分析海量数据已经成为关键挑战&#xff0c;结合传统数仓与数据湖优势的湖仓一体&#xff08;Lakehouse&#xff…

解决WSL2占用内存过多问题(Docker on WSL2: VmmemWSL)

解决WSL2占用内存过多问题&#xff08;Docker on WSL2: VmmemWSL&#xff09; 一、问题描述二、问题解决2.1 创建.wslconfig文件2.2 重启wsl2 一、问题描述 安装完WSL2后&#xff0c;又安装了Docker&#xff0c;使用了一段时间&#xff0c;发现电脑变卡&#xff0c;进一步查看…

【VUE异常】el-popconfirm失效,@confirm事件不生效,点击没有任何反应,刷新页面才能点击

el-popconfirm失效&#xff0c;confirm事件不生效&#xff0c;点击没有任何反应&#xff0c;刷新页面才能点击 一、背景描述二、原因分析三、解决方案3.1 方案一&#xff1a;使用onConfirm3.2 方案二&#xff1a;confirm与onConfirm同时使用3.3 方案三&#xff1a;el-popconfir…

【用unity实现100个游戏之12】unity制作一个俯视角2DRPG《类星露谷物语》资源收集游戏demo

文章目录 前言加快编辑器运行速度素材(1)场景人物(2)工具 一、人物移动和动画切换二、走路灰尘粒子效果探究实现 三、树木排序设计方法一方法二 四、绘制拿工具的角色动画五、砍树实现六、存储拾取物品引入Unity 的可序列化字典类 七、实现靠近收获物品自动吸附八、树木被砍掉的…

【详细教程hexo博客搭建】1、从零开始搭建一个能用的博客

1、开始 2.环境与工具准备 本教程主要面对的是Windows用户 操作系统&#xff1a;Windows10NodeGitHexo文本编辑器(强烈推荐VSCODE)GitHub 帐号一个域名&#xff08;强烈推荐买个域名&#xff09;云服务器&#xff08;可选&#xff09; 3.Node的安装 打开Node官网&#xff0…

Error: error:0308010C:digital envelope routines::unsupported

文章目录 1, 问题背景2.解决方法13.解决方法2将 React 脚本升级到 5 以上版本 3.参考资料 1, 问题背景 最近在升级我之前的一个网站的过程中&#xff0c;由于使用了高版本的nodejs v18.0.0报错如下 (undefined) assets/js/styles.1dbb3634.js from Terser Error: error:03080…

LeetCode: 4. Median of Two Sorted Arrays

LeetCode - The Worlds Leading Online Programming Learning Platform 题目大意 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。 请你找出这两个有序数组的中位数&#xff0c;并且要求算法的时间复杂度为 O(log(m n))。 你可以假设 nums1 和 nums2 不会同时为空。 …