uniapp模仿微信实现聊天界面的示例代码

目录
  • 项目演示
  • 前言
  • 主界面
  • chat.vue中引入的js文件
  • chat.vue中引入的组件
  • submit.vue中引入的组件
  • 最后

项目演示

前言

我是看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/submit.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",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 2
					}, {
						"sendName": "xpq",
						"receviceName": "゛时光い",
						"sendText": {
							"voice": "谢谢你",
							"time": 60 //秒
						},
						"createTime": "2022-01-06 12:00:12",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 2
					}, {
						"sendName": "゛时光い",
						"receviceName": "xpq",
						"sendText": "这是第九条未读消息",
						"createTime": "2022-01-03 12:22:12",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 0
					},
					{
						"sendName": "゛时光い",
						"receviceName": "xpq",
						"sendText": "这是第八条未读消息",
						"createTime": "2022-01-02 12:22:07",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 0
					},
					{
						"sendName": "xpq",
						"receviceName": "xpq",
						"sendText": "这是第七条未读消息",
						"createTime": "2021-12-19 12:22:03",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 0
					},
					{
						"sendName": "゛时光い",
						"receviceName": "xpq",
						"sendText": "这是第六条未读消息",
						"createTime": "2021-12-19 12:21:58",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 0
					},
					{
						"sendName": "゛时光い",
						"receviceName": "xpq",
						"sendText": "http://demo.rageframe.com/attachment/images/2021/11/18/image_1637224530_diIlZlmm.jpeg",
						"createTime": "2021-12-19 12:21:54",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 1
					},
					{
						"sendName": "xpq",
						"receviceName": "゛时光い",
						"sendText": "http://demo2.rageframe.com/attachment/images/2021/09/01/image_1630483477_N03W37zs.jpg",
						"createTime": "2021-12-19 12:21:48",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 1
					},
					{
						"sendName": "゛时光い",
						"receviceName": "xpq",
						"sendText": "这是第三条未读消息",
						"createTime": "2021-12-19 12:21:42",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 0
					},
					{
						"sendName": "゛时光い",
						"receviceName": "xpq",
						"sendText": "这是第二条未读消息",
						"createTime": "2021-12-19 12:21:33",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 0
					},
					{
						"sendName": "゛时光い",
						"receviceName": "xpq",
						"sendText": "http://demo2.rageframe.com/attachment/images/2021/09/01/image_1630483477_N03W37zs.jpg",
						"createTime": "2021-12-19 11:02:18",
						"updateTime": null,
						"chatmState": 1,
						"TextType": 1
					},
					{
						"sendName": "゛时光い",
						"receviceName": "xpq",
						"sendText": "爱你啊",
						"createTime": "2021-12-18 20:37:03",
						"updateTime": null,
						"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,
					longitude: e.longitude,
					name: e.name,
					address: e.address,
					success: function() {
						console.log('success');
					}
				});
			},
			//接受输入内容
			inputs(e) {
				//时间间隔处理
				let data = {
					"sendName": "゛时光い",
					"receviceName": "xpq",
					"sendText": e.message,
					"createTime": new Date(),
					"updateTime": new Date(),
					"chatmState": 1,
					"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="scss">
	page {
		height: 100%;
	}

	.content {
		height: 100%;
		background-color: rgba(244, 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, 40, 50, 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, 40, 50, 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, 40, 50, 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/noreceive.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()
				}, 10)
			},
			// 表情内发送
			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();
				}, 10)
			},
			//图片发送
			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, 244, 244, 0.96);
		border-top: 1px solid rgba(39, 40, 50, 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, 40, 50, 0.6);
		}
	}

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

		.emoji-send {
			width: 280rpx;
			height: 104rpx;
			padding-top: 24rpx;
			background-color: rgba(236, 237, 238, 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, 228, 49, 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, 237, 238, 1);
		box-shadow: 0px 11rpx 0px 0px rgba(0, 0, 0, 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, 255, 1);
				border-radius: 24rpx;
			}

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

	.voice-bg {
		height: 100%;
		width: 100%;
		background-color: rgba(0, 0, 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, 255, 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, 228, 49, 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: [
					['                        
(0)

相关推荐

  • 微信小程序uniapp实现左滑删除效果(完整代码)

    微信小程序uniapp实现左滑删除效果 实现效果 1,列表中侧滑删除 2,删除不同时存在 3,上下滑动与侧滑删除不影响 在本页面引入组件并使用 (文件在文章的最下方附上) 在需要左滑删除的地方使用 <view v-for="(item, index) in csListArrl" :key="index" :data-index="index"> <delSlideLeft :item="item" :dat

  • uniapp 实现微信小程序全局分享的示例代码

    目录 创建全局分享内容文件 引入并全局注册该文件 自定义页面分享内容  uniapp 实现微信小程序的全局转发给好友/分享到朋友圈的功能.主要使用 Vue.js 的 全局混入 概念. 下面直接上 实现步骤和代码: 创建全局分享内容文件 1.创建一个全局分享的 js 文件.示例文件路径为:@/common/share.js ,在该文件中定义全局分享的内容: export default { data() { return { // 默认的全局分享内容 share: { title: '全局分享的标

  • uniapp微信小程序实现一个页面多个倒计时

    本文实例为大家分享了uniapp实现一个页面多个倒计时的具体代码,供大家参考,具体内容如下 设计图(需求) 在这里插入图片描述 结构 <view class="group-list" v-for="item in message" :key="item.productId"> <view class="group-img" @click="navTo"> <image :src

  • uni-app自定义导航栏按钮|uniapp仿微信顶部导航条功能

    最近一直在学习uni-app开发,由于uniapp是基于vue.js技术开发的,只要你熟悉vue,基本上很快就能上手了. 在开发中发现uni-app原生导航栏也能实现一些顶部自定义按钮+搜索框,只需在page.json里面做一些配置即可.设置app-plus,配置编译到App平台的特定样式.dcloud平台对app-plus做了详细说明:app-plus配置,需注意 目前暂支持H5.App端,不支持小程序. 在page.json里配置app-plus即可 { "path": "

  • uniapp 仿微信的右边下拉选择弹出框的实现代码

    在百度找了很多 没有找到满意的 这里根据自己的需求 抽取一个组件 这个组件主要是包括搜索框和右边菜单点击弹出一个下拉筛选菜单 这里首先用一个单独的页面存放这个组件 <template> //这里是搜索框的输入框 不需要的可以删掉 <view> <view class="arrivalSearch"> <view class="arrivalSmallsearch"> <view class="arriv

  • uniapp模仿微信实现聊天界面的示例代码

    目录 项目演示 前言 主界面 chat.vue中引入的js文件 chat.vue中引入的组件 submit.vue中引入的组件 最后 项目演示 前言 我是看B站的视频一个一个敲的,讲的还不错.可以去看看vue+node.js即时通讯聊天室APP开发前端篇 主界面 chat.vue <template> <!-- 聊天界面展示https://www.bilibili.com/video/BV1hT4y1P75N?p=22 搭建1和2 --> <view class="

  • electron制作仿制qq聊天界面的示例代码

    本文介绍了electron制作仿制qq聊天界面的示例代码,分享给大家,具体如下: 效果图: 样式使用scss和flex布局 这也是制作IM系统的最后一个界面了! 在制作之前参考了qq和千牛 需要注意的点 qq将滚动条美化了 而且在无操作的情况下是不会显示的 滚动条美化 ::-webkit-scrollbar { /*滚动条整体样式*/ width: 5px; /*高宽分别对应横竖滚动条的尺寸*/ height: 1px; } ::-webkit-scrollbar-thumb { /*滚动条里面

  • Android仿微信语音聊天界面设计

    有段时间没有看视频了,昨天晚上抽了点空时间,又看了下鸿洋大神的视频教程,又抽时间写了个学习记录.代码和老师讲的基本一样,网上也有很多相同的博客.我只是在AndroidStudio环境下写的. --主界面代码-- public class MainActivity extends Activity { private ListView mListView; private ArrayAdapter<Recorder> mAdapter; private List<Recorder>

  • C# Socket编程实现简单的局域网聊天器的示例代码

    前言 最近在学习C# Socket相关的知识,学习之余,动手做了一个简单的局域网聊天器.有萌生做这个的想法,主要是由于之前家里两台电脑之间想要传输文件十分麻烦,需要借助QQ,微信或者其他第三方应用,基本都要登录,而且可能传输的文件还有大小限制,压缩问题.所以本聊天器的首要目标就是解决这两个问题,做到使用方便(双击启动即用),传文件无限制. 废话不多说,先上图.S-Chat是服务端,C-Chat是客户端,两者除了客户端首次启动后需要设置一下连接的IP地址外,无其他区别.操作与界面都完全相同,对于用

  • Android Studio实现简单的QQ登录界面的示例代码

    一.项目概述 QQ是我们日常生活使用最多的软件之一,包含登录界面和进入后的聊天界面.好友列表界面和空间动态界面等.登录界面的制作比较简单,主要考验布局的使用,是实现QQ项目的第一步.现在APP开发的首要工作都是实现登录页面,所以学会了QQ登录界面对以后的软件开发有着很重要的作用. 二.开发环境 三.详细设计 1.头像设计 首先在layout文件里面选择了RelativeLayout(相对布局)作为整个页面的布局. 在顶端放置了一个ImageView控件,宽度和高度设置的都是70dp,水平居中设置

  • Python实现网络聊天室的示例代码(支持多人聊天与私聊)

    实验名称: 网络聊天室 功能: i. 掌握利用Socket进行编程的技术 ii. 掌握多线程技术,保证双方可以同时发送 iii. 建立聊天工具 iv. 可以和单人聊天 v. 可以和多个人同时进行聊天 vi. 使用图形界面,显示双方的语录 vii. 程序可以在一定程度上进行错误识别 概述 实验通过聊天室可以完成单人或多人之间的聊天通信,功能的实现主要是通过Socket通信来实现.本次实验采用客户端/服务器(C/S)架构模式,通过Python语言来编写服务器端与客户端的程序.运用多线程可完成多点对多

  • ASP.NET MVC4异步聊天室的示例代码

    本文介绍了ASP.NET MVC4异步聊天室的示例代码,分享给大家,具体如下: 类图: Domain层 IChatRoom.cs using System; using System.Collections.Generic; namespace MvcAsyncChat.Domain { public interface IChatRoom { void AddMessage(string message); void AddParticipant(string name); void GetM

  • php实现微信和支付宝支付的示例代码

    php实现微信支付 微信支付文档地址:https://pay.weixin.qq.com/wiki/doc/api/index.html 在php下实现微信支付,这里我使用了EasyWeChat 这里我是在Yii框架实现的,安装EasyWeChat插件 composer require jianyan74/yii2-easy-wechat 一:配置EasyWeChat 1:在config/main.php 的 component中添加EasyWeChat的SDK 'components' =>

  • Java调用微信支付功能的方法示例代码

    Java 使用微信支付 前言百度搜了一下微信支付,都描述的不太好,于是乎打算自己写一个案例,希望以后拿来直接改造使用. 因为涉及二维码的前端显示,所以有前端的内容 一. 准备工作 所需微信公众号信息配置 APPID:绑定支付的APPID(必须配置) MCHID:商户号(必须配置) KEY:商户支付密钥,参考开户邮件设置(必须配置) APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置) 我这个案例用的是尚硅谷一位老师提供的,这里不方便提供出来,需要大家自己找,或者公司提供 二

  • python修改微信和支付宝步数的示例代码

    项目意义 如果你想在支付宝蚂蚁森林收集很多能量种树,为环境绿化出一份力量,又或者是想每天称霸微信运动排行榜装逼,却不想出门走路,那么该python脚本可以帮你实现. 实现方法 手机安装第三方软件乐心健康,注册账号登录,将运动数据同步到微信和支付宝.用python脚本远程修改乐心健康当前登录账号的步数即可. 第一步:在手机上安装乐心健康app. 安卓版下载地址:乐心健康安卓版 苹果版下载地址:乐心健康iOS版 乐心运动app for android v3.0 安卓版 第二步:注册账号登录,并设置登

随机推荐