uniapp:聊天消息列表(好友列表+私人单聊)支持App、H5、小程序

avatar
作者
猴君
阅读量:0

  

  

🎬 江城开朗的豌豆个人主页

 🔥 个人专栏 :《 VUE 》 《 javaScript 》

 📝 个人网站 :《 江城开朗的豌豆🫛 》 

⛺️ 生活的理想,就是为了理想的生活 !

在这里插入图片描述

目录

 ⭐  文章简介(效果图展示)        

  📟 插件传送门:聊天消息列表

 📘  文章背景

  📘 平台兼容性

 📘  功能实现

废话不说直接上代码

 📟 用户列表完整代码

 📟 单人对话框 完整代码 

🔥 文章总结

📟 隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:


 ⭐  文章简介(效果图展示)

      在现代社交互动中,聊天消息列表是应用程序中的关键组成部分。它不仅仅是一种通信工具,更是人们日常生活中连接感情、分享信息的重要方式之一。随着移动互联网的发展,用户在不同平台上(如App、H5、小程序等)进行聊天的需求也愈发增加。因此,设计并实现一个支持多平台、多种形式的聊天消息列表成为了开发者们的挑战之一。

        

    📟 插件传送门聊天消息列表

 📘  文章背景

        

       最近我专注于优化我们聊天消息列表的交互体验。现在,我们的消息列表页面上有多个标签,每个标签对应着不同的聊天会话。当用户点击某个标签时,页面会流畅地滚动到相应的聊天记录位置,这样用户就可以更方便地查看他们感兴趣的对话内容。

      今天下午,我花了些时间在消息列表的交互功能上进行调整和改进。经过一番努力,我成功地实现了这一功能!在这个过程中,我逐步解决了各种技术挑战,体验着一个个问题被一一击破的成就感。这种改进用户体验的过程真是让人感到无比满足!

  📘 平台兼容性

Vue2Vue3
App快应用微信小程序支付宝小程序百度小程序字节小程序QQ小程序
HBuilderX 3.6.11 app-vue app-nvue
钉钉小程序快手小程序飞书小程序京东小程序
H5-SafariAndroid Browser微信浏览器(Android)QQ浏览器(Android)ChromeIEEdgeFirefoxPC-Safari

 📘  功能实现

废话不说直接上代码

 📟 用户列表完整代码

<template> 	<view class="page"> 		<view class="list-item" v-for="(item,index) in users" :key="index" @click="connect(item)"> 			<view class="avatar"> 				<text class="round" v-if="item.read"></text> 				<image :src="item.avatar" mode="widthFix"></image> 			</view> 			<view class="content"> 				<view class="title"> 					<text class="name">{{ item.name }}</text> 					<text class="time">{{ item.time }}</text> 				</view> 				<view class="txt">{{ item.msg }}</view> 			</view>  		</view> 	</view> </template>  <script> 	export default { 		data() { 			return { 				options: [{ 					text: '取消', 					style: { 						backgroundColor: '#007aff' 					} 				}, { 					text: '确认', 					style: { 						backgroundColor: '#dd524d' 					} 				}], 				users: [{ 						avatar: '/static/avatar/avatar1.png', 						name: '杨涛', 						read: 1, 						time: '23:59', 						msg: '没有消息就是最好的消息' 					}, 					{ 						avatar: '/static/avatar/avatar2.jpg', 						name: '雨中漫步', 						read: 1, 						time: '23:59', 						msg: '没有消息就是最好的消息' 					}, 					{ 						avatar: '/static/avatar/avatar3.jpeg', 						name: '糖果梦境', 						read: 1, 						time: '23:59', 						msg: '没有消息就是最好的消息' 					}, 					{ 						avatar: '/static/avatar/avatar4.png', 						name: '海上日落', 						read: 1, 						time: '23:59', 						msg: '没有消息就是最好的消息' 					}, 					{ 						avatar: '/static/avatar/avatar6.png', 						name: '男朋友', 						read: 1, 						time: '23:59', 						msg: '没有消息就是最好的消息' 					}, 					{ 						avatar: '/static/avatar/avatar8.png', 						name: '女朋友', 						read: 1, 						time: '23:59', 						msg: '没有消息就是最好的消息' 					}, 					{ 						avatar: '/static/avatar/avatar5.jpeg', 						name: '静谧之夜', 						read: 1, 						time: '23:59', 						msg: '没有消息就是最好的消息' 					}, 					{ 						avatar: '/static/avatar/avatar1.png', 						name: '风吹麦浪', 						read: 0, 						time: '23:59', 						msg: '没有消息就是最好的消息' 					}, 					{ 						avatar: '/static/avatar/avatar1.png', 						name: '路过岁月', 						read: 0, 						time: '23:59', 						msg: '没有消息就是最好的消息' 					}, 					{ 						avatar: '/static/avatar/avatar1.png', 						name: '繁星点点', 						read: 0, 						time: '23:59', 						msg: '没有消息就是最好的消息' 					} 				] 			}; 		}, 		methods: { 			onClick(e) { 				console.log('点击了' + (e.position === 'left' ? '左侧' : '右侧') + e.content.text + '按钮') 			}, 			swipeChange(e, index) { 				console.log('当前状态:' + e + ',下标:' + index) 			}, 			connect(item) { 				uni.navigateTo({ 					url: `/pages/message/message?name=${item.name}&avatar=${item.avatar}` 				}) 			} 		} 	} </script>  <style lang="scss" scoped> 	.page { 		padding: 0 32rpx; 		color: #333; 	}  	.list-item { 		display: flex; 		padding: 30rpx 0; 		border-bottom: 1px solid #ccced3;  		.avatar { 			width: 90rpx; 			height: 90rpx; 			border-radius: 10rpx; 			margin-right: 20rpx; 			position: relative;  			.round { 				position: absolute; 				width: 14rpx; 				height: 14rpx; 				border-radius: 50%; 				background: #ef5656; 				top: -4rpx; 				right: -4rpx; 				z-index: 1; 			}  			image { 				width: 100%; 				height: 100%; 				border-radius: 10rpx; 			} 		}  		.content { 			flex: 1;  			.title { 				display: flex; 				justify-content: space-between;  				.name { 					font-weight: bold; 				}  				.time { 					color: #999; 					font-size: 24rpx; 				} 			}  			.txt { 				margin-top: 10rpx; 				overflow: hidden; 				text-overflow: ellipsis; 				display: -webkit-box; 				-webkit-line-clamp: 1; 				-webkit-box-orient: vertical; 				text-align: left; 				color: #999; 				font-size: 26rpx; 			} 		} 	} </style>
 📟 单人对话框 完整代码

<template> 	<view class="page"> 		<scroll-view class="scroll-view" scroll-y scroll-with-animation :scroll-top="top"> 			<view style="padding: 30rpx 30rpx 240rpx;"> 				<view class="message" :class="[item.userType]" v-for="(item,index) in list" :key="index"> 					<image :src="item.avatar" v-if="item.userType === 'friend'" class="avatar" mode="widthFix"></image> 					<view class="content" v-if="item.messageType === 'image'"> 						<image :src="item.content" mode="widthFix"></image> 					</view> 					<view class="content" v-else> 						{{ item.content }} 					</view> 					<image :src="item.avatar" v-if="item.userType === 'self'" class="avatar" mode="widthFix"></image> 				</view> 			</view> 		</scroll-view> 		<view class="tool"> 			<input type="text" v-model="content" class="input" @confirm="send" /> 			<image src="/static/photo.png" mode="widthFix" class="thumb" @click="chooseImage"></image> 		</view> 	</view> </template>  <script> 	export default { 		data() { 			return { 				content: '', 				list: [], 				top: 0 			}; 		}, 		onLoad(options) { 			uni.setNavigationBarTitle({ 				title: options.name 			}) 			this._friendAvatar = options.avatar 			this._selfAvatar = '/static/avatar/avatar5.jpeg' 			this.list = [ 				{ 					content: '对方历史回复消息', 					userType: 'friend', 					avatar: this._friendAvatar 				}, 				{ 					content: '历史消息', 					userType: 'self', 					avatar: this._selfAvatar 				} 			] 		}, 		methods: { 			send() { 				this.list.push({ 					content: this.content, 					userType: 'self', 					avatar: this._selfAvatar 				}) 				this.content = '' 				this.scrollToBottom() 				// 模拟对方回复 				setTimeout(()=>{ 					this.list.push({ 						content: '周末什么安排', 						userType: 'friend', 						avatar: this._friendAvatar 					}) 					this.scrollToBottom() 				}, 1500) 			}, 			chooseImage() { 				uni.chooseImage({ 					// sourceType: 'album', 					success: (res) => { 						this.list.push({ 							content: res.tempFilePaths[0], 							userType: 'self', 							messageType: 'image', 							avatar: this._selfAvatar 						}) 						this.scrollToBottom() 						// 模拟对方回复 						setTimeout(()=>{ 							this.list.push({ 								content: '你好呀,朋友~', 								userType: 'friend', 								avatar: this._friendAvatar 							}) 							this.scrollToBottom() 						}, 1500) 					} 				}) 			}, 			scrollToBottom() { 				this.top = this.list.length * 1000 			} 		} 	} </script>  <style lang="scss" scoped> 	.scroll-view { 		/* #ifdef H5 */ 		height: calc(100vh - 44px); 		/* #endif */ 		/* #ifndef H5 */ 		height: 100vh; 		/* #endif */ 		background: #eee; 		box-sizing: border-box; 	} 	.message { 		display: flex; 		align-items: flex-start; 		margin-bottom: 30rpx; 		 		.avatar { 			width: 80rpx; 			height: 80rpx; 			border-radius: 10rpx; 			margin-right: 30rpx; 		} 		.content { 			min-height: 80rpx; 			max-width: 60vw; 			box-sizing: border-box; 			font-size: 28rpx; 			line-height: 1.3; 			padding: 20rpx; 			border-radius: 10rpx; 			background: #fff; 			image { 				width: 200rpx; 			} 		} 		&.self { 			justify-content: flex-end; 			.avatar { 				margin: 0 0 0 30rpx; 			} 			.content { 				position: relative; 				&::after { 					position: absolute; 					content: ''; 					width: 0; 					height: 0; 					border: 16rpx solid transparent; 					border-left: 16rpx solid #fff; 					right: -28rpx; 					top: 24rpx; 				} 			} 		} 		&.friend { 			.content { 				position: relative; 				&::after { 					position: absolute; 					content: ''; 					width: 0; 					height: 0; 					border: 16rpx solid transparent; 					border-right: 16rpx solid #fff; 					left: -28rpx; 					top: 24rpx; 				} 			} 		} 	}  	.tool { 		position: fixed; 		width: 100%; 		min-height: 120rpx; 		left: 0; 		bottom: 0; 		background: #fff; 		display: flex; 		align-items: flex-start; 		box-sizing: border-box; 		padding: 20rpx 24rpx 20rpx 40rpx; 		padding-bottom: calc(20rpx + constant(safe-area-inset-bottom)/2) !important; 		padding-bottom: calc(20rpx + env(safe-area-inset-bottom)/2) !important; 		.input { 			background: #eee; 			border-radius: 10rpx; 			height: 70rpx; 			margin-right: 30rpx; 			flex: 1; 			padding: 0 20rpx; 			box-sizing: border-box; 			font-size: 28rpx; 		} 		.thumb { 			width: 64rpx; 		} 	} </style> 

 

🔥 文章总结

📟 隐私、权限声明

         如说明表达还不够清楚,不清楚怎么使用可导入完整示例项目运行体验和希望对大家有帮助!

1. 本插件需要申请的系统权限列表:

无,开箱即用

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

没有任何广告,纯分享,方便自己,同时也方便其他能用的的前端好朋友

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

使用插件有任何问题欢迎加入QQ讨论群:

作者QQ群:906392632(未满)

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!