鸿蒙OSUniApp 开发实时聊天页面的最佳实践与实现#三方框架 #Uniapp
使用 UniApp 开发实时聊天页面的最佳实践与实现
在移动应用开发领域,实时聊天功能已经成为许多应用不可或缺的组成部分。本文将深入探讨如何使用 UniApp 框架开发一个功能完善的实时聊天页面,从布局设计到核心逻辑实现,带领大家一步步打造专业级的聊天界面。
一、页面布局设计
在开发聊天页面时,合理的布局设计是保证良好用户体验的基础。一个标准的聊天页面通常包含以下几个关键部分:
- 顶部导航栏:显示聊天对象信息
- 消息列表区域:展示聊天记录
- 底部输入区域:包含输入框和功能按钮
1.1 基础页面结构
<template><view class="chat-container"><!-- 顶部导航 --><view class="chat-header"><text class="chat-title">{{chatInfo.name}}</text></view><!-- 消息列表区域 --><scroll-view class="message-list"scroll-y="true":scroll-top="scrollTop"@scrolltoupper="loadMoreMessages"><block v-for="(msg, index) in messageList" :key="index"><message-item :message="msg" :isMine="msg.senderId === userId"/></block></scroll-view><!-- 底部输入区域 --><view class="input-area"><input class="message-input"v-model="inputContent"type="text"confirm-type="send"@confirm="sendMessage"/><button class="send-btn" @tap="sendMessage">发送</button></view></view>
</template><style lang="scss">
.chat-container {display: flex;flex-direction: column;height: 100vh;background-color: #f5f5f5;.chat-header {height: 88rpx;background-color: #ffffff;display: flex;align-items: center;padding: 0 30rpx;border-bottom: 1rpx solid #eaeaea;.chat-title {font-size: 32rpx;font-weight: 500;color: #333;}}.message-list {flex: 1;padding: 20rpx;}.input-area {padding: 20rpx;background-color: #ffffff;display: flex;align-items: center;border-top: 1rpx solid #eaeaea;.message-input {flex: 1;height: 72rpx;background-color: #f5f5f5;border-radius: 36rpx;padding: 0 30rpx;margin-right: 20rpx;}.send-btn {width: 120rpx;height: 72rpx;line-height: 72rpx;text-align: center;background-color: #007AFF;color: #ffffff;border-radius: 36rpx;font-size: 28rpx;}}
}
</style>
二、核心业务逻辑实现
2.1 数据管理与状态定义
<script>
import { ref, reactive, onMounted, onUnmounted } from 'vue'
import { initWebSocket } from '@/utils/websocket'export default {setup() {// 聊天基础信息const chatInfo = reactive({name: '聊天对象',avatar: '',id: ''})// 消息列表const messageList = ref([])// 输入内容const inputContent = ref('')// 滚动位置const scrollTop = ref(0)// 当前用户IDconst userId = ref('')// WebSocket 实例let ws = null// 生命周期钩子onMounted(() => {initChatRoom()})onUnmounted(() => {ws && ws.close()})// 初始化聊天室const initChatRoom = async () => {// 获取历史消息await loadHistoryMessages()// 初始化 WebSocket 连接initWebSocketConnection()}return {chatInfo,messageList,inputContent,scrollTop,userId}}
}
</script>
2.2 WebSocket 连接管理
// utils/websocket.js
export const initWebSocket = (url, options = {}) => {const ws = uni.connectSocket({url,success: () => {console.log('WebSocket连接成功')}})ws.onOpen(() => {options.onOpen && options.onOpen()})ws.onMessage((res) => {const data = JSON.parse(res.data)options.onMessage && options.onMessage(data)})ws.onError((error) => {console.error('WebSocket错误:', error)options.onError && options.onError(error)})ws.onClose(() => {console.log('WebSocket连接关闭')options.onClose && options.onClose()})return ws
}
2.3 消息发送与接收处理
// 在 setup 函数中添加以下方法// 发送消息
const sendMessage = () => {if (!inputContent.value.trim()) returnconst message = {id: Date.now(),content: inputContent.value,senderId: userId.value,timestamp: new Date().getTime(),type: 'text'}// 发送消息到服务器ws.send({data: JSON.stringify(message),success: () => {// 本地添加消息messageList.value.push(message)// 清空输入框inputContent.value = ''// 滚动到底部scrollToBottom()}})
}// 接收消息处理
const handleReceiveMessage = (message) => {messageList.value.push(message)scrollToBottom()
}// 滚动到底部
const scrollToBottom = () => {setTimeout(() => {const query = uni.createSelectorQuery()query.select('.message-list').boundingClientRect()query.exec((res) => {if (res[0]) {scrollTop.value = res[0].height}})}, 100)
}
三、优化与性能提升
3.1 消息列表性能优化
为了提高大量消息渲染时的性能,我们可以采用以下几个优化策略:
- 虚拟列表实现:
// components/virtual-list.vue
<template><view class="virtual-list" :style="{ height: height + 'px' }"><view class="virtual-list-phantom" :style="{ height: totalHeight + 'px' }"><view class="virtual-list-content":style="{ transform: getTransform }"><block v-for="item in visibleData" :key="item.id"><message-item :message="item"/></block></view></view></view>
</template><script>
export default {props: {listData: {type: Array,default: () => []},itemHeight: {type: Number,default: 60},height: {type: Number,default: 600}},setup(props) {const start = ref(0)const end = ref(0)// 计算可视区域数据const visibleData = computed(() => {return props.listData.slice(start.value, end.value)})// 计算总高度const totalHeight = computed(() => {return props.listData.length * props.itemHeight})// 计算偏移量const getTransform = computed(() => {return `translate3d(0, ${start.value * props.itemHeight}px, 0)`})return {visibleData,totalHeight,getTransform}}
}
</script>
3.2 消息发送状态管理
// store/chat.js
import { defineStore } from 'pinia'export const useChatStore = defineStore('chat', {state: () => ({messageQueue: [], // 消息发送队列sendingMessages: new Set() // 正在发送的消息ID集合}),actions: {// 添加消息到发送队列addToQueue(message) {this.messageQueue.push(message)this.processSendQueue()},// 处理发送队列async processSendQueue() {if (this.messageQueue.length === 0) returnconst message = this.messageQueue[0]if (this.sendingMessages.has(message.id)) returnthis.sendingMessages.add(message.id)try {await this.sendMessage(message)this.messageQueue.shift()this.sendingMessages.delete(message.id)if (this.messageQueue.length > 0) {this.processSendQueue()}} catch (error) {console.error('消息发送失败:', error)this.sendingMessages.delete(message.id)}}}
})
四、实用功能扩展
4.1 消息类型支持
除了基本的文本消息,我们还可以支持图片、语音等多种消息类型:
// components/message-item.vue
<template><view class="message-item" :class="{ 'message-mine': isMine }"><image class="avatar" :src="message.avatar"/><view class="message-content"><template v-if="message.type === 'text'"><text>{{message.content}}</text></template><template v-else-if="message.type === 'image'"><image class="message-image" :src="message.content"mode="widthFix"@tap="previewImage(message.content)"/></template><template v-else-if="message.type === 'voice'"><view class="voice-message" @tap="playVoice(message)"><text>{{message.duration}}″</text></view></template></view></view>
</template>
4.2 消息输入增强
// 在输入区域组件中添加更多功能
const handleChooseImage = () => {uni.chooseImage({count: 1,success: async (res) => {const tempFilePath = res.tempFilePaths[0]// 上传图片const uploadResult = await uploadFile(tempFilePath)// 发送图片消息sendMessage({type: 'image',content: uploadResult.url})}})
}const startRecordVoice = () => {recorderManager.start({duration: 60000,format: 'mp3'})
}const stopRecordVoice = async () => {recorderManager.stop()// 处理录音结果并发送语音消息
}
总结
本文详细介绍了如何使用 UniApp 开发一个功能完善的实时聊天页面。从基础布局到核心业务逻辑,再到性能优化和功能扩展,涵盖了实际开发中的主要环节。在实际项目中,还需要根据具体需求进行定制化开发,比如添加表情包功能、消息撤回、@提醒等特性。
开发过程中要特别注意以下几点:
- WebSocket 连接的稳定性维护
- 大量消息加载时的性能优化
- 各类型消息的统一管理
- 用户体验的细节处理
希望这篇文章能够帮助大家更好地理解和实现 UniApp 聊天功能的开发。如果您在开发过程中遇到任何问题,欢迎在评论区讨论交流。
相关文章:
鸿蒙OSUniApp 开发实时聊天页面的最佳实践与实现#三方框架 #Uniapp
使用 UniApp 开发实时聊天页面的最佳实践与实现 在移动应用开发领域,实时聊天功能已经成为许多应用不可或缺的组成部分。本文将深入探讨如何使用 UniApp 框架开发一个功能完善的实时聊天页面,从布局设计到核心逻辑实现,带领大家一步步打造专…...

upload-labs通关笔记-第5关 文件上传之.ini绕过
目录 一、ini文件绕过原理 二、源码审计 三、渗透实战 1、查看提示 2、制作.user.ini文件 (1)首先创建一个文本文件 (2)保存文件名为.user.ini 2、制作jpg后缀脚本 (1)创建一个文本文件 …...

ssti模板注入学习
ssti模板注入原理 ssti模板注入是一种基于服务器的模板引擎的特性和漏洞产生的一种漏洞,通过将而已代码注入模板中实现的服务器的攻击 模板引擎 为什么要有模板引擎 在web开发中,为了使用户界面与业务数据(内容)分离而产生的&…...

填涂颜色(bfs)
归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言📝 含泪播种的人一定能含笑收获! 题目描述 由数字 0 0 0 组成的方阵中,有一任意形状的由数字 1 1 1 构成的闭合圈。现…...

ros1+docker环境快速搭建
快速使用python 解析ros1的bag消息ros这个东西可以说安装起来非常麻烦的,费时费力,很可能还安装不成功,特别是我的环境是ubuntu22.04 ,官方都不支持安装ros1。因此一个可行且快速的方法是使用别人配置好的ros的docker环境 一、下…...
vscode extention踩坑记
# npx vsce package --allow-missing-repository --no-dependencies #耗时且不稳定 npx vsce package --allow-missing-repository #用这行 code --install-extension $vsixFileName --force我问ai:为什么我的.vsix文件大了那么多 ai答:因为你没有用 --n…...

GpuGeek全栈AI开发实战:从零构建企业级大模型生产管线(附完整案例)
目录 背景一、算力困境:AI开发者的「三重诅咒」1.1 硬件成本黑洞1.2 资源调度失衡1.3 环境部署陷阱 二、三大核心技术突破GpuGeek的破局方案2.1 分时切片调度引擎(Time-Slicing Scheduler)2.2 异构计算融合架构2.3 AI资产自动化…...
【TroubleShoot】禁用Unity Render Graph API 兼容模式
使用Unity 6时新建了项目,有一个警告提示: The project currently uses the compatibility mode where the Render Graph API is disabled. Support for this mode will be removed in future Unity versions. Migrate existing ScriptableRenderPasses…...
数据库字段唯一性修复指南:从设计缺陷到规范实现
数据库字段唯一性修复指南:从设计缺陷到规范实现 一、问题背景 表结构设计缺陷: sys_user 表未对 dingtalk_user_id(钉钉用户ID)字段设置唯一性约束,导致数据重复,引发以下问题: 系统稳定性风…...

DataX从Mysql导数据到Hive分区表案例
0、下载DataX并解压到对应目录 DataX安装包,开箱即用,无需配置。 https://datax-opensource.oss-cn-hangzhou.aliyuncs.com/202308/datax.tar.gz 相关参考文档 https://github.com/alibaba/DataX/blob/master/hdfswriter/doc/hdfswriter.md 1、Hive分区…...
高性能编程相关
常见高性能编程技巧: 一,系统级性能优化:从系统架构设计考虑,例如消息队列,模块分成分级,IO读写带宽等 二,算法级性能优化:时间和空间优化 三,代码级性能优…...

vulnhub靶场——secarmy
靶机:secarmy靶机,IP地址为192.168.230.18 攻击:kali,IP地址为192.168.230.134 靶机和攻击机都采用VMware虚拟机,都采用NAT模式 端口扫描: nmap 192.168.230.18 -O -A -p- --reason -sV 21/tcp (ftp): 开…...

labview硬件采集
(1)硬件的描述 (2)实验步骤1: (3)实验步骤2 库名/路径的选择要使用32位的开发资料 (4)实验步骤3 (5)实验步骤4 找到DoSetV12() 设置返回类型 设置chan 设置state labv…...

openfeign与dubbo调用下载excel实践
一、前言 openfeign和dubbo均是rpc框架 RPC(Remote Procedure Call,远程过程调用)框架 是一种允许程序像调用本地方法一样调用远程服务器上函数的技术。它隐藏了底层网络通信的复杂性,让开发者可以专注于业务逻辑,实现…...

ISP有感自发
一、黑电平 由于传感器,即便在无光的情况下,依然会产生微小的暗电流,这些暗电流可能是噪点会影响后期的调试。因此,我们便将这些电流处理为0,成为纯黑的颜色。可以在源头消除这些误差。 如何矫正黑电平: …...

web 自动化之 PO 设计模式详解
文章目录 一、什么是 POM二、如何基于 POM 进行自动化框架架构?1、base 层封装2、pageobjects 层封装3、TestCases 层封装 三、元素和方法分离&数据分离1、哪些部分可以进行分离2、示例代码 四、总结 一、什么是 POM POM page object model 页面对象模型 WEB 自…...

NVMe简介1
它分为两部分,这里是第一部分。 NVM Express(NVMe)是一种高性能、可扩展的接口协议,用于通过PCI express(PCIe)总线,实现主机软件与NVM设备之间的通信。目前,由于NVMe SSD相比于SATA…...

【python机器学习】Day 25 异常处理
知识点: 异常处理机制debug过程中的各类报错try-except机制try-except-else-finally机制 在即将进入深度学习专题学习前,我们最后差缺补漏,把一些常见且重要的知识点给他们补上,加深对代码和流程的理解。 借助ai写代码的时候&…...

数学建模初等模型应用
一、目的 掌握初等模型的建模方法,对简单的初等模型能借助Matlab工具软件进行辅助建模、求解和检验。 二、实验内容与设计思想(设计思路、主要代码分析) 1、预测鱼的质量 (1)设计思路:使用线性回归模型预测鱼的质量…...
占位符读取标准输入缓冲区规则
1、如果标准输入缓冲区中的前若干个字符都是空白字符,%s,%d,%f都能直接跳过并且从第一个非空白字符开始读取,但%c不能,而是直接读取。 2、%s遇到空白字符时停止,不会读取遇到的空白字符。 3、%d遇到非数字…...

【MCP教程系列】SpringBoot 搭建基于 Spring AI 的 SSE 模式 MCP 服务
原文地址:https://developer.aliyun.com/article/1662946 在当今快速发展的AI技术背景下,如何高效地集成模型能力成为开发者关注的重点。本文将手把手教你如何基于 Spring AI 搭建支持 SSE(Server-Sent Events)模式的 MCP 服务 相…...
【kafka】kafka概念,使用技巧go示例
1. Kafka基础概念 1.1 什么是Kafka? Kafka是一个分布式流处理平台,用于构建实时数据管道和流式应用。核心特点: 高吞吐量:每秒可处理百万级消息持久化存储:消息按Topic分区存储在磁盘分布式架构:支持水平…...

利用散点图探索宇航员特征与太空任务之间的关系
利用散点图探索宇航员特征与太空任务之间的关系 import matplotlib.pyplot as plt import numpy as np import pandas as pdfrom flexitext import flexitext from matplotlib.patches import FancyArrowPatchplt.rcParams.update({"font.family": "Corbel&quo…...
Ubuntu 命令行显示中文输出信息
Ctrl Alt T 打开终端命令行, 输入命令: sudo apt-get install language-pack-zh-hans安装中文语言支持包 sudo apt-get install language-pack-zh-hans-base配置环境变量 sudo vim /etc/profile进入文件后,按下 a 进入编辑模式,shift ↓ \downarr…...
Linux文件编程——read函数与lseek函数
一、read函数 在 Linux 文件编程中,read 函数是一个系统调用,用于从文件描述符(File Descriptor)指向的文件或设备中读取数据到缓冲区。它是 Unix/Linux 系统编程中实现底层 I/O 操作的核心函数之一。以下是 read 函数的详细使用…...
[思维模式-38]:看透事物的关系:什么是事物的关系?事物之间的关系的种类?什么是因果关系?如何通过数学的方式表达因果关系?
一、什么是事物的关系? 事物的关系是指不同事物之间存在的各种联系和相互作用,它反映了事物之间的相互依存、相互影响、相互制约等特性。以下从不同维度为你详细阐述: 1、关系的类型 因果关系 定义:一个事件(原因&a…...
【2025.5.12】视觉语言模型 (更好、更快、更强)
【2025.5.12】Vision Language Models (Better, Faster, Stronger): https://huggingface.co/blog/vlms-2025 【2024.4.11】Vision Language Models Explained【先了解视觉语言模型是什么】: https://huggingface.co/blog/vlms nanoVLM: https://github.…...
Spring的bean的生命周期?
Spring中bean的生命周期包括以下步骤: 通过BeanDefinition获取bean的定义信息。 调用构造函数实例化bean。 进行bean的依赖注入,例如通过setter方法或Autowired注解。 处理实现了Aware接口的bean。 执行BeanPostProcessor的前置处理器。 调用初始化…...

Qwen集成clickhouse实现RAG
一、RAG概要 RAG(Retrieval-Augmented Generation,检索增强生成) 是一种结合了信息检索技术与语言生成模型的人工智能技术。旨在通过检索相关文档来增强大模型的生成能力,从而提高预测的质量和准确性。RAG模型在生成文本或回答…...

Excel分组计算求和的两种实现方案
文章目录 背景样例数据方案一、函数求和实现步骤缺点 方案二、数据透视表实现步骤优点 背景 在Excel文档中,经常会进行数据的求和计算,可使用不同的方式实现,记录下来,方便备查。 样例数据 已有商品销量信息,包含销…...