赞
踩
简介:
本篇文章带来的是仿照微信设计的聊天界面,主要涉及到三个文件;下方已有介绍,代码块中也有相关说明,直接复制然后就可使用;注意获取消息的websoket和拉取历史消息的接口还是需要自己去写,下方只做大致参考;具体消息格式下方代码块中已列出
一、聊天主界面chatIndex.vue
<template> <view class="chat"> <scroll-view class="scroll-view" :style="{height: `${windowHeight-inputHeight}rpx`}" <-- 根据键盘高度调整聊天界面高低 --> id="scrollview" scroll-y="true" :scroll-top="scrollTop" @scrolltoupper="topRefresh" @click="touchClose" > <view id="msglistview" class="chat-body"> <u-loading-icon v-if="loading" /> <view v-for="(item,index) in msgList" :key="index"> <view class="msg-time" v-if="item.isShowTime"> {{changeTime(item.sendTime)}} </view> <view class="item self" v-if="item.sendUserId == userId"> <view class="msg-menu menu-right" :style="{display: showBoxId==item.id?'block':'none'}"> <view class="tr-icon tr-icon-right"></view> <ChatMsgMenu :msgUserId="item.sendUserId" :msgId="item.id" :content="item.content" :msgSortId="index" :time="item.sendTime" @cancelMsg="cancelMsg"/> </view> <view @longpress="showBoxId=item.id"> <view class="content-text right" v-if="item.type=='text'"> {{item.content}} </view> <view class="content-text right" v-else-if="item.type=='voice'"> <view style="display: flex;" @click="playSound(item.content)"> <text>{{ item.soundTIme }}''</text> <image style="width: 42rpx;height: 42rpx;" :src="imgConf.replayChange"/> </view> </view> <view class="content-img" v-else-if="item.type=='img'"> <image class="img-style" :src="item.content" mode="widthFix" :lazy-load="true"/> </view> <view class="content-video" v-else> <video class="video-style" :src="item.content" /> </view> </view> <image class="avatar" :src="item.wxUser.headImg" /> </view> <view class="item Ai" v-else> <image class="avatar" :src="item.wxUser.headImg" /> <view @longpress="showBoxId=item.id"> <view class="content-text left" v-if="item.type=='text'"> {{item.content}} </view> <view class="content-text le ft" v-else-if="item.type=='voice'"> <view style="display: flex;" @click="playSound(item.content)"> <text>{{ item.soundTIme }}''</text> <image style="width: 42rpx;height: 42rpx;" :src="imgConf.replayChange"/> </view> </view> <view class="content-img" v-else-if="item.type=='img'"> <image class="img-style" :src="item.content" mode="widthFix" :lazy-load="true"/> </view> <view class="content-video" v-else> <video class="video-style" :src="item.content" /> </view> </view> <view class="msg-menu menu-left" :style="{display: showBoxId==item.id?'block':'none'}"> <view class="tr-icon tr-icon-left"></view> <ChatMsgMenu :msgUserId="item.sendUserId" :msgId="item.id" :content="item.content" :msgSortId="index" :time="item.sendTime" @cancelMsg="cancelMsg"/> </view> </view> </view> </view> </scroll-view> <view class="chat-bottom" :style="{height: `${inputHeight}rpx`}"> <view class="send-msg" :style="{bottom:`${keyboardHeight}rpx`}"> <view class="uni-textarea"> <image class="icon-style" :src="changeLogUrl" @click="changeInputType"/> <view class="out_textarea_box"> <textarea placeholder-class="textarea_placeholder" :style="{textAlign:(textareaConf.disabled?'center':'')}" v-model="chatMsg" maxlength="250" confirm-type="send" auto-height :placeholder="textareaConf.text" :show-confirm-bar="false" :adjust-position="false" :disabled="textareaConf.disabled" @confirm="handleSend" @linechange="sendHeight" @focus="focus" @blur="blur" @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd" /> </view> <image class="icon-style" :src="imgConf.emoji" @click="handleSend"/> <image class="icon-style" :src="imgConf.more" @click="moreMenu"/> </view> </view> <view :style="{display:showMoreMenu?'block':'none'}" class="more-menu"> <view class="inner-box"> <view class="menu" @click="sendFile('choose','')"> <view> <image class="i-style" :src="imgConf.sendphoto"></image> <view class="t-style">照片</view> </view> </view> <view class="menu" @click="sendFile('shoot','')"> <view> <image class="i-style" :src="imgConf.takePhoto"></image> <view class="t-style">拍摄</view> </view> </view> </view> </view> </view> <view class="voice-mask" v-show="voice.mask"> <view class="inner-mask"> <view class="voice-progress-box" :style="{width:`${progressNum}`+'rpx'}"> <view class="third-icon"/> <view class="progress-num"> {{ voice.length }}s </view> </view> <view class="cancel-btn" :class="{cancelBtn:voice.cancel}"> <image style="width: 60rpx;height: 60rpx;" src="http://116.205.133.116:8080/static/app/logo/publicLogo/cancelSend.png"></image> </view> <view class="show-tips"> 上滑取消发送 </view> <view class="bottom-area"> <image class="img-style" :src="imgConf.voiceBtn" /> </view> </view> </view> </view> </template> <script> import timeMethod from "@/tools/timeMethod.js"; //时间工具类 export default{ data() { return { imgConf: { //界面icon图片配置,可自定义 emoji: "http://xx/static/app/logo/publicLogo/emoji.png", more: "http://xx/static/app/logo/publicLogo/more.png", sendphoto: "http://xx/static/app/logo/publicLogo/sendPhoto.png", sendVideo: "http://xx/static/app/logo/publicLogo/video.png", takePhoto: "http://xx/static/app/logo/publicLogo/takePhoto.png", voiceBtn: "http://xx/static/app/logo/publicLogo/voiceBtn.png", keyboard: "http://xx/static/app/logo/publicLogo/keyborad.png", speak: "http://xx/static/app/logo/publicLogo/speak.png", replayChange: "http://xx/static/app/logo/publicLogo/replay.png", replay: "http://xx/static/app/logo/publicLogo/replay.png", replaing: "http://xx/static/app/logo/publicLogo/replaing.png" }, changeLogUrl: "http://xx/static/app/logo/publicLogo/speak.png", loading: false, keyboardHeight:0, bottomHeight: 0, scrollTop: 0, chatMsg: "", userId: "", //自己的userId userHeadImg: "", //自己的头像 toUserId: "", //聊天朋友的userId toUserHeadImg: "", //聊天朋友的头像 pageSize: 20, //分页数量 pageNum: 1, //分页开始数 returnPageNum: "", //接口返回的聊天信息的总页数 msgList: [], //聊天消息list judgeScrollToBottom: true, startTime: "", msgID: 0, showBoxId: "", showBoxUserId: "", showMoreMenu: false, textareaConf: { disabled: false, text: "" }, voice: { //语音录制界面配置 mask: false, //遮罩层 length: 0, //语音录制时长 cancel: false, //是否取消发送 startX: "", //获取 startY: "", timer: "", recordInstance: "", //uni语音录制实例 finished: false //是否已结束录制 }, msgConf: { showTimeSpace: 120 //消息隔多长时间才展示 } } }, updated(){ //页面更新时调用聊天消息定位到最底部 if (this.judgeScrollToBottom) { this.scrollToBottom(); } }, computed: { //获取窗口页面高度 windowHeight() { return this.rpxTopx(uni.getSystemInfoSync().windowHeight); }, // 键盘弹起来的高度+发送框高度 inputHeight(){ return this.bottomHeight+this.keyboardHeight; }, //语音录制时进度条 progressNum() { return this.voice.length*2 + 250; } }, onLoad(e){ //监听键盘高度 uni.onKeyboardHeightChange(res => { this.keyboardHeight = this.rpxTopx(res.height); if(this.keyboardHeight<=0) { this.keyboardHeight = 0; this.showMoreMenu = false; } }); //获取自己userId this.userId = uni.getStorageSync("userId"); //获取好友UserId this.toUserId = e.userId; //创建录音实例 this.voice.recordInstance = uni.getRecorderManager(); //调用websocket进行监听 this.webSocket(); this.getUserInfo(); this.getMessage(); this.readedMsg(); }, onUnload() { //关闭socket uni.closeSocket({ code: 200, success() { console.log("正常关闭") } }) }, methods: { //websocket实例 webSocket() { //消息监听 uni.onSocketMessage((res)=>{ let data = JSON.parse(res.data); this.msgList.push(data.msg); }) }, //下拉刷新,分页用的 topRefresh() { if (this.pageNum<this.returnPageNum) { this.pageNum++; this.judgeScrollToBottom = false; this.loading = true; //调用消息接口,拉去消息 this.getMessage(); } }, //获取聊天消息 getMessage() { //this.$request("/msg/getChatMessage","POST", //{"sendUserId": this.userId, //"acceptUserId": this.toUserId, //"pageSize": this.pageSize, //"pageNum": this.pageNum},{"Content-Type":"application/x-www-form-urlencoded"}).then(res=>{ //this.returnPageNum = res.data.data.pagesNum; //获取消息的总页数 //this.showMsgTime(res.data.data.data); //处理消息信息,用于在消息列表上展示消息时间 //res.data.data.data的数据消息为以下格式: //消息为四种类型-文本(text)/图片(img)/视频(video)/语音(voice),通过type来区别,content如果是text类型则直接存的文本信息,如果是其他三种则直接存链接形式 let data = [ { "id": 29, "sendUserId": "20220328001", "acceptUserId": "20220328007", "type": "text", "content": "555", "sendTime": "2023-11-11 13:48:25", "wxUser": { "nickName": "Andy", "headImg": "http://xxx/static/images/779e2a63-9d30-4db1-bace-a1d50ecb3866.jpg" } }, { "id": 28, "sendUserId": "20220328001", "acceptUserId": "20220328007", "type": "voice", "content": "http://xxx/static/images/779e2a63-9d30-4db1-bace-a1d50ecb3866.mp3", "sendTime": "2023-11-11 13:48:24", "wxUser": { "nickName": "Andy", "headImg": "http://xxx/static/images/779e2a63-9d30-4db1-bace-a1d50ecb3866.jpg" } }, { "id": 29, "sendUserId": "20220328001", "acceptUserId": "20220328007", "type": "img", "content": "http://xxx/static/images/779e2a63-9d30-4db1-bace-a1d50ecb3866.jpg", "sendTime": "2023-11-11 13:48:25", "wxUser": { "nickName": "Andy", "headImg": "http://xxx/static/images/779e2a63-9d30-4db1-bace-a1d50ecb3866.jpg" } },] this.showMsgTime(data); this.loading = false; //}) }, //消息时间展示 showMsgTime(data) { data.forEach(e=>{ e.isShowTime = false; //时间显示打标 e.sendTime = timeMethod.timeFormat(e.sendTime,"T"); this.msgID++; //消息id计数,定位消息list的索引 if (this.startTime!="") { //第一条消息前面没时间,排出掉 if (Math.abs(timeMethod.calculateTime(e.sendTime,this.startTime))/1000 > this.msgConf.showTimeSpace) { //计算消息时间间隔大于120秒 this.msgList.slice(0 - this.msgID)[0].isShowTime = true; //注入打标数据 } } this.startTime = e.sendTime; //每次循环记住该条消息时间,用于计算消息之间时间间隔 this.msgList.unshift(e); //处理好数据后push进消息list }) //消息列表最上面一条显示时间 if (this.pageNum == this.returnPageNum) { this.msgList[0].isShowTime = true; } }, //时间转变 changeTime(time) { let space = (new Date(timeMethod.timeFormat(time,"T")) - new Date(timeMethod.getNowTime().split("T")[0]+"T00:00:00"))/(1000*60*60*24); let Time =timeMethod.timeFormat(time," ").split(" "); let week = timeMethod.getDateToWeek(time); //当天 if (space > 0 && space < 1) { return Time[1].slice(0,5); } //昨天 else if (space > -1 && space < 0) { return "昨天 " + Time[1].slice(0,5); } //星期 else if (space < -1 && Math.abs(space) < timeMethod.getDateToWeek(timeMethod.getNowTime()).weekID - 1) { return week.weekName + " " + Time[1].slice(0,5); } //日期 else { return Time[0].slice(5,10) + " " + Time[1].slice(0,5); } }, //获取用户信息,这儿获取聊天好友的用户信息 getUserInfo() { this.$request("/sys/getUserName","POST",{"userId":this.userId,"toUserId":this.toUserId}, {"Content-Type":"application/x-www-form-urlencoded"}).then(res=>{ let data = res.data.data; this.userHeadImg = data[0].headImg; this.toUserHeadImg = data[1].headImg; uni.setNavigationBarTitle({ title: data[1].nickName }) }) }, //输入框聚焦 focus(){ this.scrollToBottom(); }, //输入框取消聚焦 blur(){ this.scrollToBottom(); }, // px转换成rpx rpxTopx(px){ let deviceWidth = uni.getSystemInfoSync().windowWidth; let rpx = ( 750 / deviceWidth ) * Number(px); return Math.floor(rpx); }, // 监视聊天发送栏高度 sendHeight(){ setTimeout(()=>{ let query = uni.createSelectorQuery(); query.select('.send-msg').boundingClientRect(); query.exec(res =>{ this.bottomHeight = this.rpxTopx(res[0].height); }) },200) }, // 滚动至聊天底部 scrollToBottom(e){ setTimeout(()=>{ let query = uni.createSelectorQuery().in(this); query.select('#scrollview').boundingClientRect(); query.select('#msglistview').boundingClientRect(); query.exec((res) =>{ if(res[1].height > res[0].height){ this.scrollTop = this.rpxTopx(res[1].height - res[0].height); } }) },200); }, // 发送消息 handleSend() { this.judgeScrollToBottom = true; this.pageNum = 1; //如果消息不为空 if(this.chatMsg.length!==0){ this.$request("/msg/sendMsg","POST",{ "sendUserId":this.userId, "acceptUserId":this.toUserId, "type": "text", "content":this.chatMsg}).then(res=>{ if (res.data.status=="ok") { //发送消息成功后会返回刚刚发送的消息数据,然后借push进消息list this.msgList.push(res.data.data); this.chatMsg = ""; } }) } }, //接收消息或发送消息时间显示 showTime() { let time = timeMethod.getNowTime(); if (timeMethod.calculateTime(time,this.msgList.slice(-1)[0].sendTime)/1000 > this.msgConf.showTimeSpace) { return true; }else { return false; } }, //已读消息 readedMsg() { this.$request("/msg/readedMsg","GET",{"sendUserId":this.toUserId,"acceptUserId":this.userId}) }, //语音播放 playSound(url) { this.imgConf.replayChange = this.imgConf.replaing; let music = null; music = uni.createInnerAudioContext(); music.src = url; music.play(); music.onEnded(()=>{ music = null; this.imgConf.replayChange = this.imgConf.replay; }) }, //msglist索引-删除消息list中的元素 cancelMsg(id) { //自定义的移除list元素的方法 Array.prototype.remove = function (dx) { if (isNaN(dx) || dx > this.length) { return false; } for (var i = 0, n = 0; i < this.length; i++) { if (this[i] != this[dx]) { this[n++] = this[i] } } this.length -= 1 } //直接调用移除消息list中的元素 this.msgList.remove(id); }, //语音图标切换 changeInputType() { if (this.changeLogUrl == this.imgConf.speak) { this.changeLogUrl = this.imgConf.keyboard; this.textareaConf.disabled = true; this.textareaConf.text = "按住说话"; this.chatMsg = ""; } else { this.changeLogUrl = this.imgConf.speak; this.textareaConf.disabled = false; this.textareaConf.text = ""; } }, //全局点击关闭 touchClose() { this.showBoxId = ""; this.showMoreMenu = false; this.keyboardHeight = 0; }, //更多菜单 moreMenu() { this.keyboardHeight = 300; let timer = setTimeout(()=>{this.showMoreMenu = true;},100); }, // 开始录制语音 handleTouchStart(e){ var that = this; if (this.textareaConf.disabled) { that.voice.finished = false; //手指离开按钮打标 uni.getSetting({ success(res) { if (res.authSetting['scope.record']===undefined) { console.log("第一次授权") } else if (!res.authSetting['scope.record']) { uni.showToast({ icon: "none", title: "点击右上角···进入设置开启麦克风授权!", duration: 2000 }) } else { that.voice.recordInstance.start(); that.voice.mask = true; that.voice.isRecord = true; that.voice.length = 1; that.voice.startX = e.touches[0].pageX; that.voice.startY = e.touches[0].pageY; that.voice.timer = setInterval(() => { that.voice.length += 1; if(that.voice.length >= 60) { clearInterval(that.voice.timer); that.handleTouchEnd(); } },1000) //判断先结束按钮但是录制才开始时不会结束录制的条件;因为获取授权这儿存在延时;所以结束录制时可能还没开始录制 if (that.voice.finished && that.voice.mask) { that.handleTouchEnd(); } } } }) } }, // 语音录制时滑动事件 handleTouchMove(e){ if (this.textareaConf.disabled) { if (this.voice.startY - e.touches[0].pageY >100) { this.voice.cancel = true; }else { this.voice.cancel = false; } } }, // 语音录制结束 handleTouchEnd(){ if (this.textareaConf.disabled) { this.voice.finished = true; this.voice.mask = false; clearInterval(this.voice.timer); this.voice.recordInstance.stop(); this.voice.recordInstance.onStop((res) => { const message = { voice:res.tempFilePath, length:this.voice.length } if (!this.voice.cancel) { if (this.voice.length>1) { this.sendFile("voice",message); } else { uni.showToast({ icon: 'none', title: "语音时间太短", duration: 1000 }) } }else { this.voice.cancel = false; } }) } }, //发送文件 sendFile(type,data) { var that = this; if (type=="choose") { uni.chooseMedia({ count: 1, mediaType: ['image', 'video'], sourceType: ['album'], maxDuration: 30, success(res) { let type = 'img'; if (res.tempFiles[0].fileType=='image') { type = 'img' } else { type = 'video' } that.uploadFile(res.tempFiles[0].tempFilePath,type) } }) } else if (type=="shoot") { uni.chooseMedia({ count: 1, mediaType: ['image', 'video'], sourceType: ['camera'], maxDuration: 30, success(res) { let type = 'img'; if (res.tempFiles[0].fileType=='image') { type = 'img' } else { type = 'video' } that.uploadFile(res.tempFiles[0].tempFilePath,type) } }) } else { that.uploadFile(data.voice,'voice') } }, uploadFile(path,type) { var that = this; let data = {"sendUserId":this.userId,"acceptUserId":this.toUserId,"type":type}; if (type=='voice') { data = {"sendUserId":this.userId,"acceptUserId":this.toUserId,"type":type,"time":this.voice.length}; } uni.uploadFile({ url: '接口地址', filePath: path, name: 'file', formData: data, header: {"token": this.$store.state.token}, success(res) { let newMsg = JSON.parse(res.data) //上传成功后,接口会返回消息数据 格式与上方的消息时一样的,然后把返回的数据push到消息list中 that.msgList.push(newMsg.data) } }) } } } </script> <style lang="scss"> $chatContentbgc: #C2DCFF; $sendBtnbgc: #4F7DF5; center { display: flex; align-items: center; justify-content: center; } /* 聊天消息 */ .chat { .topTabbar { width: 100%; height: 90rpx; line-height: 90rpx; display: flex; margin-top: 80rpx; justify-content: space-between; .icon { margin-left: 20rpx; } .text { margin: auto; font-size: 16px; font-weight: 700; } .button { width: 10%; margin: auto 20rpx auto 0rpx; } } .scroll-view { ::-webkit-scrollbar { display: none; width: 0 !important; height: 0 !important; -webkit-appearance: none; background: transparent; color: transparent; z-index: 0; } background-color: #F6F6F6; .chat-body { display: flex; flex-direction: column; padding-top: 23rpx; .self { justify-content: flex-end; position: relative; } .Ai { position: relative; } .item { display: flex; padding: 23rpx 30rpx; .right { background-color: $chatContentbgc; } .left { background-color: #FFFFFF; } .right::after { position: absolute; display: inline-block; content: ''; width: 0; height: 0; left: 100%; top: 10px; border: 12rpx solid transparent; border-left: 12rpx solid $chatContentbgc; } .left::after { position: absolute; display: inline-block; content: ''; width: 0; height: 0; top: 10px; right: 100%; border: 12rpx solid transparent; border-right: 12rpx solid #FFFFFF; } .content-text { position: relative; max-width: 486rpx; border-radius: 8rpx; word-wrap: break-word; padding: 24rpx 24rpx; margin: 0 24rpx; border-radius: 5px; font-size: 32rpx; font-family: PingFang SC; font-weight: 500; color: #333333; line-height: 42rpx; } .content-img { margin: 0 24rpx; } .content-video { margin: 0 24rpx; } .img-style { width: 400rpx; height: auto; border-radius: 10rpx; } .video-style { width: 400rpx; height: 400rpx; } .avatar { display: flex; justify-content: center; width: 78rpx; height: 78rpx; background: $sendBtnbgc; border-radius: 50rpx; overflow: hidden; image { align-self: center; } } .msg-menu { min-width: 100rpx; height: 100rpx; display: none; background: #383838; position: absolute; border-radius: 10rpx; z-index: 100; .tr-icon { position: absolute; top: 100rpx; width: 0; height: 0; border: 15rpx solid transparent; border-top: 15rpx solid #383838; } .tr-icon-left { left: 15rpx; } .tr-icon-right { right: 15rpx; } } .menu-left { top: -100rpx; left: 120rpx; } .menu-right { top: -100rpx; right: 120rpx; } } } .msg-time { font-size: 24rpx; text-align: center; color: #737373; } } .chat-bottom { width: 100%; height: auto; background: #F4F5F7; transition: all 0.25s ease; .send-msg { display: flex; align-items: flex-end; padding: 16rpx 30rpx; width: 100%; min-height: 150rpx; position: fixed; bottom: 0; background: #fff; transition: all 0.25s ease; .uni-textarea { width: 100%; padding-bottom: 40rpx; display: flex; align-items: center; .icon-style { width: 60rpx; height: 60rpx; padding: 0rpx 10rpx ; } .out_textarea_box { width:65%; min-height: 80rpx; max-height: 200rpx; border-radius: 40rpx; background: #f1f1f1; display: flex; justify-content: center; align-items: center; textarea { width:86%; min-height: 42rpx; max-height: 200rpx; background: #f1f1f1; font-size: 32rpx; font-family: PingFang SC; color: #333333; } } } } } .more-menu { width: 100%; min-height: 300rpx; margin-top: 150rpx; display: none; position: fixed; bottom: 0rpx; .inner-box { width: 98%; height: 280rpx; margin: 10rpx 1%; display: flex; .menu { width: 120rpx; height: 130rpx; background: #ffffff; margin: 20rpx; border-radius: 20rpx; display: flex; align-items: center; justify-content: center; .i-style { width: 80rpx; height: 80rpx; } .t-style { font-size: 22rpx; font-weight: 600; text-align: center; } } } } .voice-mask{ position:fixed; top:0; right:0; bottom:0; left:0; background-color: rgba(0,0,0,0.8); .inner-mask { display: flex; flex-direction: column; align-items: center; .voice-progress-box { min-width: 250rpx; height: 150rpx; margin-top: 60%; border-radius: 50rpx; background: #4df861; position: relative; @extend center; .third-icon { width: 0; height: 0; border: 15rpx solid transparent; border-top: 15rpx solid #4df861; position: absolute; top: 100%; left: 45%; } .progress-num { font-size: 50rpx; font-weight: 600; } } .cancel-btn { width: 120rpx; height: 120rpx; clip-path: circle(); margin-top: 50%; background: #080808; @extend center; } .cancelBtn { width: 150rpx; height: 150rpx; } .show-tips { width: 100%; margin-top: 80rpx; text-align: center; color: white; animation: 4s opacity2 1s infinite; font-size: 30rpx; font-weight: 400; font-family: sans-serif; } @keyframes opacity2{ 0%{opacity:0} 50%{opacity:.8;} 100%{opacity:0;} } .bottom-area { position: fixed; bottom: 0rpx; width: 100%; height:190rpx; border-top: #BABABB 8rpx solid; border-radius: 300rpx 300rpx 0 0; background-image: linear-gradient(#949794,#e1e3e1); @extend center; .img-style { width: 50rpx; height: 50rpx; } } } } } view,button,text,input,textarea { margin: 0; padding: 0; box-sizing: border-box; } //去除scroll-view的滑动条 ::-webkit-scrollbar { display: none; width: 0 !important; height: 0 !important; -webkit-appearance: none; background: transparent; } </style>
二、timeMethod.js 工具类,在聊天界面会被引入
class TimeMethod { constructor() {} //日期格式化 addZero(data) { if (parseInt(data) < 10) { return "0" + String(data); } return data; } /** * 获取当前日期 */ getNowTime() { var myDate = new Date(); let year = myDate.getFullYear(); let mouth = this.addZero(myDate.getMonth()); let day = this.addZero(myDate.getDate()); let hour = this.addZero(myDate.getHours()); let minute = this.addZero(myDate.getMinutes()); let second = this.addZero(myDate.getSeconds()); return year + '-' + String((parseInt(mouth)+1)) + '-' + day + 'T' + hour+ ':' + minute+ ':' + second } /** * @param {Object} timestamp * @param {Object} type * 时间戳转时间 */ timestampToTime(timestamp,type) { if(String(timestamp).length===10) { //时间戳为10位需*1000 var date = new Date(timestamp * 1000); }else { var date = new Date(timestamp); } var Y = date.getFullYear() + '-'; var M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1) + '-'; var D = date.getDate() + ' '; var h = date.getHours() + ':'; var m = date.getMinutes() + ':'; var s = date.getSeconds(); if(type==="date") { return Y+M+D; }else { return Y+M+D+h+m+s; } } /** * @param {Object} time * 时间转时间戳 */ timeToTimestamp(time) { //精确到秒,毫秒用000代替 :Date.parse(date); return new Date(time).getTime(); } /** * @param {Object} startTime * @param {Object} endTime * 日期计算 */ calculateTime(startTime,endTime) { return new Date(startTime) - new Date(endTime) } /** * @param {Object} time * 日期转星期 */ getDateToWeek(time) { let weekArrayList = [ {"weekID":7,"weekName":"星期日"}, {"weekID":1,"weekName":"星期一"}, {"weekID":2,"weekName":"星期二"}, {"weekID":3,"weekName":"星期三"}, {"weekID":4,"weekName":"星期四"}, {"weekID":5,"weekName":"星期五"}, {"weekID":6,"weekName":"星期六"}]; return weekArrayList[new Date(time).getDay()] } /** * @param {Object} date * yyyy-MM-dd HH:mm:ss转为 yyyy-MM-ddTHH:mm:ss */ timeFormat(date,type) { if (type == "T") return date.replace(" ","T") else return date.replace("T"," ") } /** * @param {Object} time * 定时器 */ timeSleep(time) { return new Promise((resolve)=>setTimeout(resolve,time)) } } export default new TimeMethod();
三、消息菜单组件 ChatMsgMenu.vue(会在消息功能菜单中引用,长按消息会显示该菜单),组件使用的uniapp easycome模式,直接拿来使用即可
<template> <view class="menu-box"> <view v-for="item,index in menuList" :key="item.id"> <view class="menu-box-inner" v-if="msgUserId==userId || !item.isShowSelf" @click="clickMenu(item.type,content)"> <image class="menu-icon" :src="item.icon" /> <view class="text-style">{{ item.name }}</view> </view> </view> </view> </template> <script> export default { props: { msgUserId: { type: String, default: "" }, msgId: { type: Number, default: 0 }, msgSortId: { type: Number, default: 0 }, content: { type: String, default: "" } ,time: { type: String, default: "" } }, data() { return { menuList: [ {"id":1,"isShowSelf":true,"name":"撤回","type":"cancel","icon":"http://xxx/static/app/logo/publicLogo/cancel.png"}, {"id":2,"isShowSelf":false,"name":"复制","type":"copy","icon":"http://xxx/static/app/logo/publicLogo/copy.png"}, {"id":3,"isShowSelf":false,"name":"引用","type":"quote","icon":"http://xxx/static/app/logo/publicLogo/quote.png"} ], userId: uni.getStorageSync("userId") } }, methods: { //点击菜单 clickMenu(type,text) { switch(type) { case "cancel": this.delMsg(); break; case "copy": this.copyText(text) break; default: console.log(type) } }, //撤回消息 delMsg() { this.$request("/msg/delMsg","DELETE",{"msgId":this.msgId},{"Content-Type":"application/x-www-form-urlencoded"}).then(res=>{ if (res.data.status=="ok") { uni.showToast({ icon: "none", title: "消息已撤回", duration: 1000 }) this.$emit("cancelMsg",this.msgSortId); } }) }, //复制信息 copyText(text) { wx.setClipboardData({ data: text, success(res) { wx.getClipboardData({ success(res) { uni.showToast({ icon: 'none', title: "复制成功", duration: 1000 }) } }) } }) } } } </script> <style lang="scss"> center { display: flex; align-items: center; justify-content: center; } .menu-box { min-width: 100rpx; height: 100rpx; @extend center; .menu-box-inner { width: 90rpx; @extend center; flex-direction: column; .menu-icon { width: 45rpx; height: 45rpx; } .text-style { font-size: 23rpx; color: #e6e6e6; } } } </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。