Uniapp 实现图文聊天功能
下面我将介绍如何在 Uniapp 中实现一个基本的图文聊天功能,包括消息发送、接收和展示。
一、准备工作
- 创建 Uniapp 项目
- 准备后端接口(可以使用云开发、自己的服务器或第三方服务)
二、实现步骤
1. 页面结构
<template>
<view class="chat-container">
<!-- 聊天消息区域 -->
<scroll-view
class="message-list"
scroll-y="true"
:scroll-with-animation="true"
:scroll-top="scrollTop"
>
<view
v-for="(item, index) in messageList"
:key="index"
:class="['message-item', item.isMe ? 'my-message' : 'other-message']"
>
<!-- 头像 -->
<image
class="avatar"
:src="item.isMe ? myAvatar : otherAvatar"
mode="aspectFill"
></image>
<!-- 消息内容 -->
<view class="message-content">
<!-- 文本消息 -->
<text v-if="item.type === 'text'" class="text-message">{{ item.content }}</text>
<!-- 图片消息 -->
<image
v-else-if="item.type === 'image'"
class="image-message"
:src="item.content"
mode="widthFix"
@click="previewImage(item.content)"
></image>
</view>
</view>
</scroll-view>
<!-- 输入区域 -->
<view class="input-area">
<!-- 图片选择按钮 -->
<view class="action-btn" @click="chooseImage">
<uni-icons type="image" size="24" color="#666"></uni-icons>
</view>
<!-- 文本输入框 -->
<input
class="input-box"
v-model="inputText"
placeholder="输入消息..."
@confirm="sendTextMessage"
/>
<!-- 发送按钮 -->
<view class="send-btn" @click="sendTextMessage">
<text>发送</text>
</view>
</view>
</view>
</template>
2. JavaScript 逻辑
<script>
export default {
data() {
return {
messageList: [], // 消息列表
inputText: '', // 输入文本
scrollTop: 0, // 滚动位置
myAvatar: '/static/avatars/my-avatar.jpg', // 我的头像
otherAvatar: '/static/avatars/other-avatar.jpg', // 对方头像
socket: null // WebSocket 连接
}
},
onLoad() {
this.initWebSocket();
// 加载历史消息
this.loadHistoryMessages();
},
onUnload() {
// 关闭 WebSocket 连接
if (this.socket) {
this.socket.close();
}
},
methods: {
// 初始化 WebSocket
initWebSocket() {
// 这里替换为你的 WebSocket 地址
this.socket = new WebSocket('wss://your-websocket-url.com');
this.socket.onopen = () => {
console.log('WebSocket 连接成功');
};
this.socket.onmessage = (res) => {
const message = JSON.parse(res.data);
this.receiveMessage(message);
};
this.socket.onerror = (err) => {
console.error('WebSocket 错误:', err);
};
this.socket.onclose = () => {
console.log('WebSocket 连接关闭');
};
},
// 加载历史消息
loadHistoryMessages() {
// 这里调用你的 API 获取历史消息
uni.request({
url: 'https://your-api-url.com/messages',
success: (res) => {
this.messageList = res.data.messages;
this.scrollToBottom();
}
});
},
// 发送文本消息
sendTextMessage() {
if (!this.inputText.trim()) return;
const message = {
id: Date.now(),
type: 'text',
content: this.inputText,
isMe: true,
time: new Date().toLocaleTimeString()
};
// 添加到消息列表
this.messageList.push(message);
this.inputText = '';
// 发送到服务器
this.sendToServer(message);
// 滚动到底部
this.$nextTick(() => {
this.scrollToBottom();
});
},
// 选择图片
chooseImage() {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePaths = res.tempFilePaths;
this.uploadImage(tempFilePaths[0]);
}
});
},
// 上传图片
uploadImage(filePath) {
uni.showLoading({ title: '上传中...' });
// 这里替换为你的上传 API
uni.uploadFile({
url: 'https://your-api-url.com/upload',
filePath: filePath,
name: 'file',
success: (uploadRes) => {
const res = JSON.parse(uploadRes.data);
if (res.code === 0) {
const message = {
id: Date.now(),
type: 'image',
content: res.data.url,
isMe: true,
time: new Date().toLocaleTimeString()
};
this.messageList.push(message);
this.sendToServer(message);
this.$nextTick(() => {
this.scrollToBottom();
});
}
},
complete: () => {
uni.hideLoading();
}
});
},
// 发送消息到服务器
sendToServer(message) {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify(message));
} else {
// 如果 WebSocket 不可用,使用 HTTP 请求
uni.request({
url: 'https://your-api-url.com/send',
method: 'POST',
data: message,
success: () => {
console.log('消息发送成功');
}
});
}
},
// 接收消息
receiveMessage(message) {
message.isMe = false; // 标记为对方消息
this.messageList.push(message);
this.$nextTick(() => {
this.scrollToBottom();
});
},
// 预览图片
previewImage(url) {
uni.previewImage({
urls: this.messageList
.filter(item => item.type === 'image')
.map(item => item.content),
current: url
});
},
// 滚动到底部
scrollToBottom() {
// 这里需要根据实际内容高度计算
this.scrollTop = 99999;
}
}
}
</script>
3. CSS 样式
<style>
.chat-container {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f5f5f5;
}
.message-list {
flex: 1;
padding: 20rpx;
overflow: auto;
}
.message-item {
display: flex;
margin-bottom: 30rpx;
}
.my-message {
flex-direction: row-reverse;
}
.other-message {
flex-direction: row;
}
.avatar {
width: 80rpx;
height: 80rpx;
border-radius: 10rpx;
}
.message-content {
max-width: 60%;
margin: 0 20rpx;
}
.text-message {
padding: 15rpx 20rpx;
border-radius: 10rpx;
background-color: #fff;
font-size: 28rpx;
line-height: 1.5;
}
.my-message .text-message {
background-color: #95ec69;
}
.image-message {
max-width: 100%;
border-radius: 10rpx;
}
.input-area {
display: flex;
align-items: center;
padding: 20rpx;
background-color: #fff;
border-top: 1rpx solid #eee;
}
.input-box {
flex: 1;
height: 70rpx;
padding: 0 20rpx;
margin: 0 20rpx;
border-radius: 35rpx;
background-color: #f5f5f5;
font-size: 28rpx;
}
.action-btn {
padding: 10rpx;
}
.send-btn {
padding: 10rpx 20rpx;
color: #007aff;
font-size: 28rpx;
}
</style>
三、功能扩展建议
- 消息状态:添加发送中、已发送、已读等状态
- 消息撤回:实现消息撤回功能
- 语音消息:添加语音消息功能
- 表情包:支持表情包发送
- 消息分页:实现消息分页加载
- 离线消息:处理离线消息同步
- 消息加密:增加消息加密功能
四、注意事项
- 实际开发中需要替换示例中的 API 地址和 WebSocket 地址
- 图片上传需要根据后端接口调整参数
- 生产环境需要考虑安全性、性能优化等问题
- 对于复杂的聊天应用,建议使用成熟的即时通讯 SDK(如融云、环信等)
这个实现提供了基本的图文聊天功能,你可以根据实际需求进行扩展和优化。