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

70 篇文章 8 订阅
4 篇文章 1 订阅

  

  

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

 🔥 个人专栏 :《 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

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

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

  • 107
    点赞
  • 100
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 151
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 151
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江城开朗的豌豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值