1. 程式人生 > 程式設計 >uniapp模仿微信實現聊天介面的示例程式碼

uniapp模仿微信實現聊天介面的示例程式碼

目錄
  • 專案演示
  • 前言
  • 主介面
  • chat.中引入的檔案
  • chat.vue中引入的元件
  • submit.vue中引入的元件
  • 最後

專案演示

uniapp模仿微信實現聊天介面的示例程式碼

前言

我是看B站的視訊一個一個敲的,講的還不錯。可以去看看vue+node.js即時通訊聊天室APP開發前端篇

主介面

chat.vue

<template>
	<!-- 聊天介面展示https://www.bilibili.com/video/BV1hT4y1P75N?p=22  搭建1和2 -->
	<view class="content">

		<!-- 聊天內容 -->
		<scroll-view class="chat" scroll-y="true" scroll-with-animation="true" :scroll-into-view="scrollToView">
			<view class="chat-main" :style="{paddingBottom:inputh+'px'}">
				<view class="chat-ls" v-for="(item,index) in unshiftmsg" :key="index" :id="'msg'+ index">
					<view class="chat-time" v-if="item.createTime != ''">{{changeTime(item.createTime)}}</view>
					<view class="msg-m msg-left" v-if="item.sendName ==  friendName">
						<image class="user-img" src="../../../static/logo.png"></image>
						<view class="message" v-if="item.TextType == 0">
							<!-- 文字 -->
							<view class="msg-text">{{item.sendText}}</view>
						</view>
						<view class="message" v-if="item.TextType == 1" @tap="previewImg(item.sendText)">
							<!-- 影象 -->
							<image :src="item.sendText" class="msg-img" mode="widthFix"></image>
						</view>
						<view class="message" v-if="item.TextType == 2" @tap="playVoice(item.sendText.voice)">
							<!-- 音訊 -->
							<view class="msg-text voice" :style="{width:item.sendText.time*4+'rpx'}">
								<image src="../../../static/icon/Hotline.png" class="voice-img"></image>
								{{item.sendText.time}}″
							</view>
						</view>
						<view class="message" v-if="item.TextType == 3" @tap="openLocation(item.sendText)">
						
<!-- 位置 --> <view class="msg-map"> <view class="map-name">{{item.sendText.name}}</view> <view class="map-address">{{item.sendText.address}}</view> <!-- 如果map不起作用,就可以直接用一張圖片去替代 --> <map class="map" :longitude="item.sendText.longitude" :latitude="item.sendText.latitude" :markers="covers(item.sendText)"></map> </view> </view> </view> <view class="msg-m msg-right" v-if="item.sendName != friendName"> <image class="user-img" src="../../../static/logo.png"></image> <view class="message" v-if="item.TextType == 0"> 客棧
<view class="msg-text">{{item.sendText}}</view> </view> <view class="message" v-if="item.TextType == 1" @tap="previewImg(item.sendText)"> <image :src="item.sendText" class="msg-img" mode="widthFix"></image> </view> <view class="message" v-if="item.TextType == 2" @tap="playVoice(item.sendText.voice)"> <!-- 音訊 --> <view class="msg-text voice" :style="{width:item.sendText.time*4+'rpx'}"> {{item.sendText.time}}″ <image src="../../../static/icon/Hotline.png" class="voice-img"></image> </view> </view> <view class="message" v-if="item.TextType == 3" @tap="openLocation(item.sendText)"> <!-- 位置 --> <view class="msg-map"> <view class="map-name">{{item.sendText.name}}</view> <view class="map-address">{{item.sendText.address}}</view> <map class="map" :longitude="item.sendText.longitude" :latitude="item.sendText.latitude" :markers="covers(item.sendText)"></map> </view> </view> </view> </view> </view> </scroll-view> <submit @inputs="inputs" @heights="heights"></submit> </view> </template> <script> import dateTime from '../../../common/dateTime.js'; import submit from '../../../components/submit/subm
it.vue'; //音訊播放 const innerAudioContext = uni.createInnerAudioContext(); export default { data() { return { friendName: "xpq",msg: [{ "sendName": "xpq","receviceName": "゛時光い","sendText": { "address": "湖南省岳陽市湘陰縣新世紀大道","latitude": 28.68925,"longitude": 112.90917,"name": "湘陰縣政府(新世紀大道北)",},"createTime": "2022-01-06 12:40:12","updateTime": null,"chatmState": 1,"TextType": 3 },{ "sendName": "゛時光い","receviceName": "xpq","sendText": { "voice": "時光匆匆流過","time": 2 //秒 },"createTime": "2022-01-06 12:22:12","TextType": 2 },{ "sendName": "xpq","sendText": { "voice": "謝謝你","time": 60 //秒 },"createTime": "2022-01-06 12:00:12","sendText": "這是第九條未讀訊息","createTime": "2022-01-03 12:22:12","TextType": 0 },"sendText": "這是第八條未讀訊息","createTime": "2022-01-02 12:22:07","sendText": "這是第七條未讀訊息","createTime": "2021-12-19 12:22:03","sendText": "這是第六條未讀訊息","createTime": "2021-12-19 12:21:58","sendText": "http://demo.rageframe.com/attachment/images/2021/11/18/image_1637224530_diIlZlmm.jpeg","createTime": "2021-12-19 12:21:54","TextType": 1 },"sendText": "http://demo2.rageframe.com/attachment/images/2021/09/01/image_1630483477_N03W37zs.jpg","createTime": "2021-12-19 12:21:48","sendText": "這是第三條未讀訊息","createTime": "2021-12-19 12:21:42","sendText": "這是第二條未讀訊息","createTime": "2021-12-19 12:21:33","createTime": "2021-12-19 11:02:18","sendText": "愛你啊","createTime": "2021-12-18 20:37:03","chatmState": 0,"TextType": 0 } ],// 反轉資料接收 unshiftmsg: [],imgMsg: [],scrollToView: '',oldTime: new Date(),inputh: '60' } },onShow() { // 陣列倒敘 主要是應對後端傳過來的資料 for (var i = 0; i < this.msg.length; i++) { //時間間隔處理 if (i < this.msg.length - 1) { //這裡表示頭部時間還是顯示一下 let t = dateTime.spaceTime(this.oldTime,this.msg[i].createTime); if (t) { this.oldTime = t; } this.msg[i].createTime = t; } // 獲取圖片,為下面的預覽做準備 if (this.msg[i].TextType == 1) { this.imgMsg.unshift(this.msg[i].sendText) } this.unshiftmsg.unshift(this.msg[i]); } // 跳轉到最後一條資料 與前面的:id進行對照 this.$nextTick(function() { this.scrollToView = 'msg' + (this.unshiftmsg.length - 1) }) },components: { submit,methods: { changeTime(date) { return dateTime.dateTime1(date); },// 進行圖片的預覽 previewImg(e) { let index = 0; for (let i = 0; i < this.imgMsg.length; i++) { if (this.imgMsg[i] == e) { index = i; } } console.log("index",index) // 預覽圖片 uni.previewImage({ current: index,urls: this.imgMsg,longPressActions: { itemList: ['傳送給朋友','儲存圖片','收藏'],success: function(data) { console.log('選中了第' + (data.tapIndex + 1) + '個按鈕,第' + (data.index + 1) + '張圖片'); },fail: function(err) { console.log(err.errMsg); } } }); },//音訊播放 playVoice(e) { innerAudioContext.src = e; innerAudioContext.onPlay(() => { console.log('開始播放'); }); },//地圖定位 covers(e) { let map = [{ latitude: e.latitude,longitude: e.longitude,iconPath: '../../../static/logo.png' }] return (map); },//跳轉地圖資訊 openLocation(e) { uni.openLocation({ latitude: e.latitude,name: e.name,address: e.address,success: function() { console.log('success'); } }); },//接受輸入內容 inputs(e) { //時間間隔處理 let data = { "sendName": "゛時光い","sendText": e.message,"createTime": new Date(),"updateTime": new Date(),"TextType": e.type }; // 傳送給伺服器訊息 // onSendWS(JSON.stringify(data)); this.unshiftmsg.push(data); // 跳轉到最後一條資料 與前面的:id進行對照 this.$nextTick(function() { this.scrollToView = 'msg' + (this.unshiftmsg.length - 1) }) if (e.type == 1) { this.imgMsg.push(e.message); } console.log(e) },//輸入框高度 heights(e) { console.log("高度:",e) this.inputh = e; this.goBottom(); },// 滾動到底部 goBottom() { this.scrollToView = ''; this.$nextTick(function() { this.scrollToView = 'msg' + (this.unshiftmsg.length - 1) }) } } } </script> <style lang="s"> page { height: 100%; } .content { height: 100%; background-color: rgba(244,244,1); } .chat { height: 100%; .chat-main { padding-left: 32rpx; padding-right: 32rpx; padding-top: 20rpx; // padding-bottom: 120rpx; //獲取動態高度 display: flex; flex-direction: column; } .chat-ls { .chat-time { font-size: 24rpx; color: rgba(39,40,50,0.3); line-height: 34rpx; padding: 10rpx 0rpx; text-align: center; } .msg-m { display: flex; padding: 20rpx 0; .user-img { flex: none; width: 80rpx; height: 80rpx; border-radius: 20rpx; } .message { flex: none; max-width: 480rpx; } .msg-text { font-size: 32rpx; color: rgba(39,1); line-height: 44rpx; padding: 18rpx 24rpx; } .msg-img { max-width: 400rpx; border-radius: 20rpx; } .msg-map { background: #fff; width: 464rpx; height: 284rpx; overflow: hidden; .map-name { font-size: 32rpx; color: rgba(39,1); line-height: 44rpx; padding: 18rpx 24rpx 0 24rpx; //下面四行是單行文字的樣式 display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden; } .map-address { font-size: 24rpx; color: rgba(39,0.4); padding: 0 24rpx; //下面四行是單行文字的樣式 display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden; } .map { padding-top: 8rpx; width: 464rpx; height: 190rpx; } } .voice { // width: 200rpx; min-width: 100rpx; max-width: 400rpx; } .voice-img { width: 28rpx; height: 36rpx; } } .msg-left { flex-direction: row; .msg-text { margin-left: 16rpx; background-color: #fff; border-radius: 0rpx 20rpx 20rpx 20rpx; } .ms-img { margin-left: 16rpx; } .msh-map { margin-left: 16rpx; border-radius: 0rpx 20rpx 20rpx 20rpx; } .voice { text-align: right; } .voice-img { float: left; transform: rotate(180deg); width: 28rpx; height: 36rpx; padding-bottom: 4rpx; } } .msg-right { flex-direction: row-reverse; .msg-text { margin-right: 16rpx; background-color: rgba(255,228,49,0.8); border-radius: 20rpx 0rpx 20rpx 20rpx; } .ms-img { margin-right: 16rpx; } .msh-map { margin-left: 16rpx; border-radius: 20rpx 0rpx 20rpx 20rpx; } .voice { text-align: left; } .voice-img { float: right; padding: 4rpx; width: 28rpx; height: 36rpx; } } } } </style>

chat.vue中引入的js檔案

dateTime.js

export default{
	//首頁時間轉化
	dateTime(e){
		let old = new Date(e);
		let now = new Date();
		//獲取old具體時間
		let d = old.getTime();
		let h = old.getHours();
		let m = old.getMinutes();
		let Y = old.getFullYear();
		let M = old.getMonth()+1;
		let D = old.getDate();
		//獲取now具體時間
		let nd =now.getTime();
		let nh = now.getHours();
		let n = now.getMinutes();
		let nY = now.getFullYear();
		let nM = now.getMonth()+1;
		let nD = now.getDate();
		
		//當天的時間
		if(D === nD && M === nM && Y === nY){
			if(h<10){
				h = '0'+h;
			}
			if(m<10){
				m = '0'+m;
			}
			return h+':'+m;
		}
		//昨天時間
		if(D+1 === nD && M === nM && Y === nY){
			if(h<10){
				h = '0'+h;
			}
			if(m<10){
				m = '0'+m;
			}
			return '昨天 '+h+':'+m;
		}else{
			//大於兩天
			return Y+'/'+M+'/'+D;
		}
		
	},//聊天時,傳送時間處理
	dateTime1(e){
		let old = new Date(e);
		let now = new Date();
		//獲取old具體時間
		let d = old.getTime();
		let h = old.getHours();
		let m = old.getMinutes();
		let Y = old.getFullYear();
		let M = old.getMonth()+1;
		let D = old.getDate();
		//獲取now具體時間
		let nd =now.getTime();
		let nh = now.getHours();
		let n = now.getMinutes();
		let nY = now.getFullYear();
		let nM = now.getMonth()+1;
		let nD = now.getDate();
		
		//當天的時間
		if(D === nD && M === nM && Y === nY){
			if(h<10){
				h = '0'+h;
			}
			if(m<10){
				m = '0'+m;
			}
			return h+':'+m;
		}
		//昨天時間
		if(D+1 === nD && M === nM && Y === nY){
			if(h<10){
				h = '0'+h;
			}
			if(m<10){
				m = '0'+m;
			}
			return '昨天 '+h+':'+m;
		}else if( Y == nY){
			//今年
			if(h<10){
				h = '0'+h;
			}
			if(m<10){
				m = '0'+m;
			}
			return M+'月'+D+'日 '+h+':'+m
		}else{
			//大於今年
			if(h<10){
				h = '0'+h;
			}
			if(m<10){
				m = '0'+m;
			}
			return Y+'年'+ M +'月' +D+ '日 '+h+':'+m
		}
	},// 間隔時間差
	spaceTime(old,now){
		old = new Date(old);
		now = new Date(now);
		var told = old.getTime();
		var tnow = now.getTime();
		if(told > (tnow+1000*60*5)){
			return now;
		}else{
			return '';
		}
	}
}

chat.vue中引入的元件

submit.vue

<template>
	<view>
		<view class="submit">
			<view class="submit-chat">
				<view class="bt-img" @tap="records">
					<image :src="toc"></image>
				</view>
				<!-- 文字框 -->
				<textarea auto-height="true" class="chat-send btn" :class="{displaynone:isrecord}" @input="inputs"
					@focus="focus" v-model="msg"></textarea>
				<view class="record btn" :class="{displaynone:!isrecord}" @touchstart="touchstart" @touchend="touchend"
					@touchmove="touchmove">
					按住說話
				</view>
				<view class="bt-img" @tap="emoji">
					<image src="../../static/icon/commonproblem.png"></image>
				</view>
				<view class="bt-img" @tap="more">
					<image src="../../static/icon/news.png"></image>
				</view>
			</view>
			<!-- 表情 -->
			<view class="emoji" :class="{displaynone:!isemoji}">
				<view class="emoji-send">
					<view class="emoji-send-det" @tap="emojiBack">
						<image src="../../static/icon/leftbrackets.png"></image>
					</view>
					<view class="emoji-send-bt" @tap="emojiSend">傳送</view>
				</view>
				<emoji @emotion="emotion" :height="260"></emoji>
			</view>
			<!-- 更多 -->
			<view class="more" :class="{displaynone:!ismore}">
				<view class="more-list" @tap="sendImg('album')">
					<image src="../../static/icon/noreceive.png"></image>
					<view class="more-list-title">圖片</view>
				</view>
				<view class="more-list" @tap="sendImg('camera')">
					<image src="../../static/icon/noreceive.png"></image>
					<view class="more-list-title">拍照</view>
				</view>
				<view class="more-list" @tap="choseLocation">
					<image src="../../static/icon/noreceive.png"></image>
					<view class="more-list-title">定位</view>
				</view>
				<view class="more-list">
					<image src="../../static/icon/noreceive.png"></image>
					<view class="more-list-title">視訊</view>
				</view>
				<view class="more-list">
					<image src="../../static/icon/noreceoazjUQINive.png"></image>
					<view class="more-list-title">檔案</view>
				</view>
			</view>
		</view>
		<view class="voice-bg" :class="{displaynone:!voicebg}">
			<view class="voice-bg-len">
				<view class="voice-bg-time" :style="{width:vlength/0.6+'%'}">
					{{vlength}}″
				</view>
				<view class="voice-del">上滑取消錄音</view>
			</view>
		</view>
	</view>
</template>

<script>
	// 引入元件
	import emoji from '../emoji/emoji.vue'
	// 錄音
	const recorderManager = uni.getRecorderManager();

	export default {
		data() {
			return {
				isrecord: false,isemoji: false,ismore: false,voicebg: false,pageY: 0,msg: "",// 直接引用地址可能出不來,需要用require
				toc: require('../../static/icon/allorder.png'),timer: '',//計時器
				vlength: 0
			};
		},components: {
			emoji,methods: {
			//獲取高度方法
			getElementHeight() {
				const query = uni.createSelectorQuery().in(this);
				query.select('.submit').boundingClientRect(data => {
					this.$emit('heights',data.height);
				}).exec();
			},//切換音訊
			records() {
				//切換的時候關閉其他介面
				this.ismore = false
				this.isemoji = false
				//切換高度
				setTimeout(() => {
					this.getElementHeight();
				},10)
				if (this.isrecord) {
					this.isrecord = false;
					this.toc = require("../../static/icon/allorder.png");
				} else {
					this.isrecord = true;
					this.toc = require("../../static/icon/wechat.png");
				}
			},// 表情
			emoji() {
				this.isemoji = !this.isemoji;
				//切換的時候關閉其功能
				this.ismore = false
				this.isrecord = false;
				this.toc = require("../../static/icon/allorder.png");
				//切換高度
				setTimeout(() => {
					this.getElementHeight();
				},10)
			},//接收表情
			emotion(e) {
				console.log(e),this.msg = this.msg + e
			},//文字傳送
			inputs(e) {
				var chatm = e.detail.value;
				var pos = chatm.indexOf('\n');
				// 檢索字串沒有資料,返回-1
				// if (pos != -1 && chatm.length > 1) {
				// this.$emit('inputs',this.msg);
				// setTimeout(() => {
				// 	this.msg = '';
				// },0)
				// }

				if (pos != -1 && chatm.length > 1) {
					// 0為表情和文字
					this.send(this.msg,0)
				}

			},// 輸入框聚焦
			focus() {
				//關閉其他項
				this.isemoji = false;
				this.ismore = false;
				setTimeout(() => {
					this.getElementHeight()
				},// 表情內傳送
			emojiSend() {
				// if (this.msg.length > 0) {
				// 	this.$emit('inputs',this.msg);
				// 	setTimeout(() => {
				// 		this.msg = '';
				// 	},0)
				// }

				if (this.msg.length > 0) {
					//0為表情和文字
					this.send(this.msg,0)
				}
			},// 表格退格
			emojiBack() {
				if (this.msg.length > 0) {
					this.msg = this.msg.substring(0,this.msg.length - 1);
				}
			},//更多功能
			more() {
				this.ismore = !this.ismore;
				//切換的時候關閉其他介面
				this.isemoji = false
				this.isrecord = false;
				this.toc = require("../../static/icon/allorder.png");
				setTimeout(() => {
					this.getElementHeight();
				},//圖片傳送
			sendImg(e) {
				let count = 9;
				if (e == 'album') {
					count = 9;
				} else {
					count = 1;
				}
				uni.chooseImage({
					count: count,//預設9
					sizeType: ['original','compressed'],//可以指定是原圖還是壓縮圖,預設二者都有
					sourceType: [e],//從相簿選擇
					// success: function (res) { //用function的方式會找不到send方法
					success: (res) => {
						console.log(JSON.stringify(res.tempFilePaths));
						const filePaths = res.tempFilePaths;
						for (let i = 0; i < filePaths.length; i++) {
							this.send(filePaths[i],1)
						}
					}
				});
			},//音訊處理
			//開始錄音
			touchstart(e) {
				console.log("開始錄音")
				console.log("點選產生資料",e)
				this.pageY = e.changedTouches[0].pageY;
				this.voicebg = true;
				let i = 1;
				this.timer = setInterval(() => {
					this.vlength = i;
					i++;
					console.log("計時器開始工作,第幾秒",i)
					//結束計時
					if (i > 60) {
						clearInterval(this.timer);
						this.touchend();
					}
				},1000)
				recorderManager.start();
			},//刪除錄音
			touchmove(e) {
				// console.log("滑動到的y軸高度:",e.changedTouches[0].pageY);
				if (this.pageY - e.changedTouches[0].pageY > 100) {
					// 關閉錄音介面
					this.voicebg = false;
				}
			},// 結束錄音
			touchend() {
				console.log("結束錄音")
				clearInterval(this.timer);
				recorderManager.stop();
				// recorderManager.onStop(function(res) {
				recorderManager.onStop((res) => {
					let data = {
						voice: res.tempFilePath,time: this.vlength
					}
					if (this.voicebg) {
						this.send(data,2);
					}
					// //時長歸位
					this.vlength = 0;
					this.voicebg = false;
					console.log('recorder stop' + JSON.stringify(res));
					// self.voicePath = res.tempFilePath;
				});
			},//獲取位置
			choseLocation() {
				uni.chooseLocation({
					// success: function(res) {
					success: res => {
						let data = {
							name: res.name,address: res.address,latitude: res.latitude,longitude: res.longitude
						}
						this.send(data,3);
						// console.log('位置名稱:' + res.name);
						// console.log('詳細地址:' + res.address);
						// console.log('緯度:' + res.latitude);
						// console.log('經度:' + res.longitude);
						
					}
				});
			},//傳送
			send(msg,type) {
				let date = {
					message: msg,type: type
				}
				this.$emit('inputs',date);
				setTimeout(() => {
					this.msg = '';
				},0)
			}
		}
	};
</script>

<style lang="scss" scoped>
	.submit {
		background: rgba(244,0.96);
		border-top: 1px solid rgba(39,0.1);
		width: 100%;
		position: fixed;
		bottom: 0;
		z-index: 100;
		// padding-bottom: var(--status-bar-height);
		padding-bottom: env(safe-area-inset-bottom);
	}

	.displaynone {
		display: none;
	}

	.submit-chat {
		width: 100%;
		display: flex;
		align-items: flex-end;
		box-sizing: border-box;
		padding: 14rpx 14rpx;

		image {
			width: 56rpx;
			height: 56rpx;
			margin: 0 10rpx;
			flex: auto;
		}

		.btn {
			flex: auto;
			background-color: #fff;
			border-radius: 10rpx;
			padding: 20rpx;
			max-height: 160rpx;
			margin: 0 10rpx;
		}

		.chat-send {
			line-height: 44rpx;
		}

		.record {
			line-height: 44rpx;
			text-align: center;
			font-size: 20rpx;
			color: rgba(39,www.cppcns.com50,0.6);
		}
	}

	.emoji {
		width: 100%;
		height: 460rpx;
		background: rgba(236,237,238,1);
		box-shadow: 0px 11rpx 0px 0px rgba(0,0.1);

		.emoji-send {
			width: 280rpx;
			height: 104rpx;
			padding-top: 24rpx;
			background-color: rgba(236,0.8);
			position: fixed;
			// bottom: 0;
			bottom: env(safe-area-inset-bottom);
			right: 0;
			display: flex;

			.emoji-send-bt {
				flex: 1;
				margin: 0 32rpx 0 20rpx;
				height: 80rpx;
				background: rgba(255,1);
				font-size: 32rpx;
				text-align: center;
				line-height: 80rpx;
				border-radius: 12rpx;
			}

			.emoji-send-det {
				flex: 1;
				margin-left: 24rpx;
				height: 80rpx;
				background: #fff;
				font-size: 32rpx;
				text-align: center;
				line-height: 80rpx;
				border-radius: 12rpx;

				image {
					width: 42rpx;
					height: 32rpx;
				}
			}
		}
	}

	.more {
		width: 100%;
		height: 436rpx;
		background: rgba(236,0.1);
		bottom: env(safe-area-inset-bottom);
		padding: 8rpx 20rpx;
		box-sizing: border-box;

		.more-list {
			width: 25%;
			text-align: center;
			float: left;
			padding-top: 32rpx;

			image {
				width: 72rpx;
				height: 72rpx;
				padding: 24rpx;
				background: rgba(255,255,1);
				border-radius: 24rpx;
			}

			.more-list-title {
				font-size: 24rpx;
				color: rgba(39,0.5);
				line-height: 34rpx;
			}
		}
	}

	.voice-bg {
		height: 100%;
		width: 100%;
		background-color: rgba(0,0.3);
		position: fixed;
		top: 0;
		bottom: 0;
		z-index: 1001;

		.voice-bg-len {
			height: 84rpx;
			width: 600rpx;
			position: absolute;
			left: 0;
			right: 0;
			top: 0;
			bottom: 0;
			margin: auto;
			background-color: rgba(255,0.2);
			border-radius: 42rpx;
			text-align: center;
		}

		.voice-bg-time {
			display: inline-block;
			min-width: 120rpx;
			line-height: 84rpx;
			background-color: rgba(255,1);
			border-radius: 42rpx;
		}

		.voice-del {
			position: absolute;
			bottom: -480rpx;
			width: 100%;
			text-align: center;
			color: #fff;
			font-size: 28rpx;
		}
	}
</style>

submit.vue中引入的元件

emoji.vue

<template>
	<view class="emoji" :style="{height:height+'px'}">
		<view class="emoji-line" v-for="(line,i) in emoji" :key="i">
			<view class="emoji-line-item" v-for="(item,index) in line" :key="index" @tap="clickEmoji(item)">{{item}}
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		props:{
			height:{
				type:Number,default:260
			}
		},name: "emoji",data() {
			return {
				emoji: [
					['