文章目录
-
- 概要
- 整体架构流程
- 技术名词解释
- 技术细节
- 小结
概要
uniapp基于vue3,小程序的聊天功能
项目是基于node.js服务器搭建的简易双向通信网页,实现了实时更新在线人数以及用户间即时通讯的功能。
整体架构流程
后台接口代码
1、首先我们可以通过Express 应用程序生成器快速搭建一个后台框架。(这快可以参考官网)
2、服务端
/**
* WebSocket模块
*/
const { WebSocketServer } = require('ws');
// 端口号
const server = new WebSocketServer({ port: 8082 });
// 存储聊天信息
let chatInfo = []
// 存储在线用户
let onlineUser = []
server.on("connection", (socket, req, res) => {
console.log('链接成功');
// 用户注册
// 获取当前连接websocket的用户uid
let uid = req.url.substr(1)
socket["id"] = uid
let index = onlineUser.findIndex(val => val.id === uid)
if (index == -1) {
onlineUser.push(socket)
}
// 从客户端接收消息
socket.on("message", (data) => {
// 将收到的消息转成对象格式
let msg = data.toString()
let message = JSON.parse(msg)
// console.log(message, '123456789');
// 通知当前用户消息发送成功
socket.send(JSON.stringify({
message: message.message,
types: message.types,
toid: message.fid,
tip: 0
}))
// 存储当前用户发送的数据
chatInfo.push({
from: uid,
to: message.fid,
message: message.message,
types: message.types
})
// console.log(onlineUser);
// 根据fid匹配到接收消息的用户并发送通知
onlineUser.forEach(item => {
if (item.id == message.fid) {
console.log("发送消息成功");
item.send(JSON.stringify({
message: message.message,
types: message.types,
from: uid,
tip: 1
}))
}
})
});
// 连接关闭后清除在线用户
socket.on('close', res => {
let newUserArr = []
let newUserIds = []
for (let i = 0; i < onlineUser.length; i++) {
let val = onlineUser[i]
if (val.id !== uid) {
newUserArr.push(val)
newUserIds.push(val.id)
}
}
onlineUser = newUserArr
let User = JSON.stringify({
onlineUser: newUserIds,
type: 'users'
})
onlineUser.forEach((client) => client.websocket.send(User))
console.log('用户离开了');
})
socket.send(JSON.stringify({
msg: '连接已建立',
type: 'system'
}))
});
3、用户端(好友列表)
3.1、首先在onLoad生命周期中判断是否链接后端
onLoad(() => {
uni.connectSocket({
url: 'ws://localhost:8082/' + store.userid,
success: data => {
console.log(data);
}
})
uni.onSocketOpen(function(res) {
socketOpen = true;
for (var i = 0; i < socketMsgQueue.length; i++) {
sendSocketMessage(socketMsgQueue[i]);
}
socketMsgQueue = [];
});
uni.onSocketClose(function(res) {
console.log('WebSocket 已关闭!');
});
uni.onSocketError(function(res) {
console.log('WebSocket连接打开失败,请检查!');
});
receiveSocketMsg()
})
3.2、获取好友列表
// 获取好友数据
const getFrineds = () => {
uni.request({
url: 'http://localhost:3461/wsb/getfreind',
data: {
uid: store.userid,
},
method: 'POST',
success: (data) => {
let code = data.data.code
if (code == 200) {
let res = data.data.query
if (res.length > 0) {
for (let i = 0; i < res.length; i++) {
List.value.push(res[i])
}
}
List.value = myfun.paixu(List.value, 'lastTime', 0)
// console.log(List.value);
// 获取好友内信息
for (let i = 0; i < List.value.length; i++) {
getLastMsg(List.value, i)
getunread(List.value, i)
}
} else {
uni.showToast({
title: "服务器出错啦!",
icon: "none",
duration: 2000
})
}
}
})
}
3.3、好友列表实时通信
// socket聊天数据接收
const receiveSocketMsg = () => {
uni.onSocketMessage(function(res) {
console.log('收到服务器内容123:' + res.data);
const msggs = JSON.parse(res.data)
let nmsg = ''
if (msggs.types == 0) {
nmsg = msggs.message
} else if (msggs.types == 1) {
nmsg = '[图片]'
} else if (msggs.types == 2) {
nmsg = '[音频]'
} else if (msggs.types == 3) {
nmsg = '[位置]'
}
for (let i = 0; i < List.value.length; i++) {
if (List.value[i].id == msggs.from) {
let e = List.value[i]
e.lastTime = new Date()
e.msg = nmsg
e.tip++
// 删除原来数据项
List.value.splice(i, 1)
// 新消息插入到最顶部
List.value.unshift(e)
// 更改最后一条消息时间
uni.request({
url: 'http://localhost:3461/wsb/updatetime',
data: {
uid: store.userid,
fid: msggs.from
},
method: 'POST',
success: (data) => {
let code = data.data.code
if (code == 200) {} else {
uni.showToast({
title: "服务器出错啦!",
icon: "none",
duration: 2000
})
}
}
})
}
}
});
}
效果:
如果还没有打开就会是未读消息,消息数加一,就在我们的头像右上角,大家可以看到小红数,当打开聊天框后小红数才会消失
4、用户端(聊天页面)
4.1、用户端uniapp是一个基于vue3的框架,首先在onMounted生命周期中判断是否链接后端
onMounted(() => {
uni.connectSocket({
// 接口
url: 'ws://localhost:8082/' + user.uid,
success: data => {
console.log(data);
}
});
uni.onSocketOpen(function(res) {
socketOpen = true;
for (var i = 0; i < socketMsgQueue.length; i++) {
sendSocketMessage(socketMsgQueue[i]);
}
socketMsgQueue = [];
});
uni.onSocketClose(function(res) {
console.log('WebSocket 已关闭!');
});
uni.onSocketError(function(res) {
console.log('WebSocket连接打开失败,请检查!');
});
receiveSocketMsg()
})
4.2、获取好友聊天内容,把内容存储到List数组中
const getList = () => {
uni.request({
url: 'http://localhost:3461/wsb/msg',
data: {
uid: user.uid,
fid: friend.fid
},
method: 'POST',
success: (data) => {
let code = data.data.code
if (code == 200) {
let msg = data.data.query
msg.reverse()
if (msg.length > 0) {
// console.log(msg);
let oldtime = msg[0].time
let imgarr = []
for (var i = 1; i < msg.length; i++) {
// 时间间隔
if (i < msg.length - 1) {
let t = myfun.spaceTime(oldtime, msg[i].time)
if (t) {
oldtime = t
}
msg[i].time = t
}
// 匹配最大时间
if (msg[i].time > oldTime.value) {
oldTime.value = msg[i].time
}
// 补充图片地址
if (msg[i].types == 1) {
msg[i].message = 'http://localhost:3461/' + msg[i].message
imgarr.push(msg[i].message)
}
// json字符串还原
if (msg[i].types == 3) {
msg[i].message = JSON.parse(msg[i].message)
}
// List.value.unshift(msg[i])
nextTick(() => {
scrollToView.value = 'msg' + List.value[i - 1].id
})
}
// 两个数组拼接
List.value = msg.concat(List.value)
getimg.value = imgarr.concat(getimg.value)
}
} else {
uni.showToast({
title: "服务器出错啦!",
icon: "none",
duration: 2000
})
}
}
})
}
4.3、把你要发送的内容发给服务器,然后在看服务器是否接收
// 聊天数据发送给服务端(socket)
const sendSocket = (e) => {
uni.request({
url: 'http://localhost:3461/wsb/insertMsg',
data: JSON.stringify({
msg: e.message,
types: e.types,
uid: user.uid,
fid: friend.fid
}),
method: 'POST',
success: (data) => {
let code = data.data.code
if (code == 200) {
// console.log("添加成功");
} else {
uni.showToast({
title: "服务器出错啦!",
icon: "none",
duration: 2000
})
}
}
})
// json字符串还原
if(e.types == 2){
e.message = JSON.parse(e.message)
}
uni.sendSocketMessage({
data: JSON.stringify({
message: e.message,
types: e.types,
uid: user.uid,
fid: friend.fid
})
});
}
4.4、服务器接收到消息后存储到用户消息里面,然后发送给客户端
// socket聊天数据接收
const receiveSocketMsg = () => {
uni.onSocketMessage(function(res) {
console.log('收到服务器内容123:' + res.data);
const msggs = JSON.parse(res.data)
if (msggs.from == friend.fid && msggs.tip==1) {
let len = List.value.length;
let nowTime = new Date()
// 时间间隔
let t = myfun.spaceTime(oldTime.value, nowTime)
if (t) {
oldTime.value = t
}
// 判断是否加ip
if (msggs.types == 1) {
msggs.message = 'http://localhost:3461' + msggs.message
}
if ( msggs.types == 2) {
msggs.message.voice = 'http://localhost:3461' + msggs.message.voice
}
nowTime = t
let data = {
fromId: msggs.from, //发送者的id
imgurl: friend.fimgurl,
time: nowTime,
message: msggs.message,
types: msggs.types,
id: len
};
List.value.push(data)
// 图片
if (msggs.types == 1) {
getimg.value.push(msggs.message)
}
nextTick(() => {
scrollToView.value = 'msg' + len
})
}
});
}
表情效果:
表情可以看作是线上文字交流的重要补充。相较于面对面的沟通,人们在线上文字对话时较难感知对方的状态或情绪,而发送表情刚好可以弥补这一缺憾。
语音效果:
语音可以帮助我们快速回复对方,在发语音时,我们可以通过声音来表达自己的想法和情感,与对方进行交流和互动。
完整代码
完成效果:
服务端文章来源:https://www.toymoban.com/news/detail-843493.html
/**
* WebSocket模块
*/
const { WebSocketServer } = require('ws');
// 端口号
const server = new WebSocketServer({ port: 8082 });
// 存储聊天信息
let chatInfo = []
// 存储在线用户
let onlineUser = []
server.on("connection", (socket, req, res) => {
console.log('链接成功');
// 用户注册
// 获取当前连接websocket的用户uid
let uid = req.url.substr(1)
socket["id"] = uid
let index = onlineUser.findIndex(val => val.id === uid)
if (index == -1) {
onlineUser.push(socket)
}
// 从客户端接收消息
socket.on("message", (data) => {
// 将收到的消息转成对象格式
let msg = data.toString()
let message = JSON.parse(msg)
// console.log(message, '123456789');
// 通知当前用户消息发送成功
socket.send(JSON.stringify({
message: message.message,
types: message.types,
toid: message.fid,
tip: 0
}))
// 存储当前用户发送的数据
chatInfo.push({
from: uid,
to: message.fid,
message: message.message,
types: message.types
})
// console.log(onlineUser);
// 根据fid匹配到接收消息的用户并发送通知
onlineUser.forEach(item => {
if (item.id == message.fid) {
console.log("发送消息成功");
item.send(JSON.stringify({
message: message.message,
types: message.types,
from: uid,
tip: 1
}))
}
})
});
// 连接关闭后清除在线用户
socket.on('close', res => {
let newUserArr = []
let newUserIds = []
for (let i = 0; i < onlineUser.length; i++) {
let val = onlineUser[i]
if (val.id !== uid) {
newUserArr.push(val)
newUserIds.push(val.id)
}
}
onlineUser = newUserArr
let User = JSON.stringify({
onlineUser: newUserIds,
type: 'users'
})
onlineUser.forEach((client) => client.websocket.send(User))
console.log('用户离开了');
})
socket.send(JSON.stringify({
msg: '连接已建立',
type: 'system'
}))
});
客户端:文章来源地址https://www.toymoban.com/news/detail-843493.html
<!-- 详情页 -->
<template>
<view class="chatroom">
<view class="top-bar">
<view class="top-bar-left" @click="back">
<image src="../../../static/icons/返回.png" class="back-img"></image>
</view>
<view class="top-bar-center">
<view class="title">
{{friend.fname}}
</view>
</view>
</view>
<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 List" :key="index" :id="'msg'+item.id">
<view class="chat-time" v-if="item.time != ''">
{{Datas(item.time)}}
</view>
<!-- 左用户 -->
<view class="msg-m msg-left" v-if="item.fromId != user.uid">
<image :src="item.imgurl" class="user-img"></image>
<!-- 文字 -->
<view class="massage" v-if="item.types == 0">
<view class="msg-text">
{{item.message}}
</view>
</view>
<!-- 图片 -->
<view class="massage" v-if="item.types == 1">
<image :src="item.message" mode="widthFix" class="msg-img" @tap="previewImg(item.message)">
</image>
</view>
<!-- 音频 -->
<view class="massage" v-if="item.types == 2">
<view class="msg-text voice" :style="{width:item.message.time*4+'px'}"
@tap="playVoice(item.message.voice)">
<image src="../../../static/submit/yp.png" class="voice-img" mode=""></image>
{{item.message.time}}″
</view>
</view>
<!-- 定位 -->
<view class="massage" v-if="item.types == 3">
<view class="msg-map" @click="openLocations(item.message)">
<view class="map-name">
{{item.message.name}}
</view>
<view class="map-address">
{{item.message.address}}
</view>
<image src="../../../static/submit/dt.jpg" class="map" mode="aspectFill"></image>
<!-- <map class="map" :longitude="item.message.longitude" :latitude="item.message.latitude"
:markers="covers(item.message)"></map> -->
</view>
</view>
</view>
<!-- 右用户 -->
<view class="msg-m msg-right" v-if="item.fromId == user.uid">
<image :src="item.imgurl" class="user-img"></image>
<view class="massage" v-if="item.types == 0">
<view class="msg-text">
{{item.message}}
</view>
</view>
<!-- 照片 -->
<view class="massage" v-if="item.types == 1">
<image :src="item.message" mode="widthFix" class="msg-img" @tap="previewImg(item.message)">
</image>
</view>
<!-- 音频 -->
<view class="massage" v-if="item.types == 2">
<view class="msg-text voice" :style="{width:item.message.time*4+'px'}"
@tap="playVoice(item.message.voice)">
{{item.message.time}}″
<image src="../../../static/submit/yp.png" class="voice-img" mode=""></image>
</view>
</view>
<!-- 定位 -->
<view class="massage" v-if="item.types == 3">
<view class="msg-map" @click="openLocations(item.message)">
<view class="map-name">
{{item.message.name}}
</view>
<view class="map-address">
{{item.message.address}}
</view>
<!-- <map class="map" :longitude="item.message.longitude" :latitude="item.message.latitude"
:markers="covers(item.message)"></map> -->
<image src="../../../static/submit/dt.jpg" class="map" mode="aspectFill"></image>
</view>
</view>
</view>
</view>
</view>
<view class="padbt"></view>
</scroll-view>
<!-- 底部导航栏 -->
<submit></submit>
</view>
</template>
<script setup>
import submit from '@/pages/buyCar/chat/submit.vue'
import {
onLoad,
} from '@dcloudio/uni-app'
import datas from '@/pages/buyCar/datas.js'
import myfun from '@/pages/buyCar/myfun.js'
// pinia
import {
useStore
} from '@/store/users.js'
// 获取用户id
const store = useStore()
// 用户信息
const user = reactive({
uid: '',
uimgurl: '',
uname: ''
})
// 获取用户信息
const getUser = () => {
user.uid = store.userid
user.uimgurl = store.uimgurl
user.uname = store.uname
}
import {
nextTick,
onMounted,
reactive,
ref
} from "vue";
// 音频
const innerAudioContext = uni.createInnerAudioContext();
// 总数据
const List = ref([]) //获取所以消息
const getimg = ref([]) //获取所以图片
const oldTime = ref(0) //时间差
const scrollToView = ref('') // 让他定位到最后一条数据
const inputh = ref(72)
// websocket信息存储
var socketOpen = false;
var socketMsgQueue = [];
// 对方的信息(前面的页面传递过来的信息)
const friend = reactive({
fid: '',
fimgurl: '',
fname: ''
})
// 进页面渲染(获取聊天数据)
onLoad((options) => {
friend.fid = options.id
friend.fimgurl = options.img
friend.fname = options.name
getUser()
getList()
})
onMounted(() => {
uni.connectSocket({
// 接口
url: 'ws://localhost:8082/' + user.uid,
success: data => {
console.log(data);
}
});
uni.onSocketOpen(function(res) {
socketOpen = true;
for (var i = 0; i < socketMsgQueue.length; i++) {
sendSocketMessage(socketMsgQueue[i]);
}
socketMsgQueue = [];
});
uni.onSocketClose(function(res) {
console.log('WebSocket 已关闭!');
});
uni.onSocketError(function(res) {
console.log('WebSocket连接打开失败,请检查!');
});
receiveSocketMsg()
})
// const getList1 = () => {
// let msg = datas.message()
// for (let i = 0; i < msg.length; i++) {
// msg[i].imgurl = '../../../static/' + msg[i].imgurl;
// // 时间间隔
// if (i < msg.length - 1) {
// let t = myfun.spaceTime(new Date(), msg[i].time)
// if (t) {
// oldTime = t
// }
// msg[i].time = t
// }
// // 补充图片地址
// if (msg[i].types == 1) {
// msg[i].message = '../../../static/' + msg[i].message;
// getimg.value.unshift(msg[i].message)
// }
// List.value.unshift(msg[i])
// nextTick(() => {
// scrollToView.value = 'msg' + List.value[i - 1].tip
// })
// }
// // 让他定位到最后一条数据
// // console.log(List.value);
// // console.log(scrollToView.value);
// }
const getList = () => {
uni.request({
url: 'http://localhost:3461/wsb/msg',
data: {
uid: user.uid,
fid: friend.fid
},
method: 'POST',
success: (data) => {
let code = data.data.code
if (code == 200) {
let msg = data.data.query
msg.reverse()
if (msg.length > 0) {
// console.log(msg);
let oldtime = msg[0].time
let imgarr = []
for (var i = 1; i < msg.length; i++) {
// 时间间隔
if (i < msg.length - 1) {
let t = myfun.spaceTime(oldtime, msg[i].time)
if (t) {
oldtime = t
}
msg[i].time = t
}
// 匹配最大时间
if (msg[i].time > oldTime.value) {
oldTime.value = msg[i].time
}
// 补充图片地址
if (msg[i].types == 1) {
msg[i].message = 'http://localhost:3461/' + msg[i].message
imgarr.push(msg[i].message)
}
// json字符串还原
if (msg[i].types == 3) {
msg[i].message = JSON.parse(msg[i].message)
}
// List.value.unshift(msg[i])
nextTick(() => {
scrollToView.value = 'msg' + List.value[i - 1].id
})
}
// 两个数组拼接
List.value = msg.concat(List.value)
getimg.value = imgarr.concat(getimg.value)
}
} else {
uni.showToast({
title: "服务器出错啦!",
icon: "none",
duration: 2000
})
}
}
})
}
// 接收输入框的内容
// uni.$on('inputs', (e) => {
// // console.log(e);
// let len = List.value.length;
// let nowTime = new Date()
// // 时间间隔
// let t = myfun.spaceTime(new Date(), nowTime)
// if (t) {
// oldTime = t
// }
// nowTime = t
// let data = {
// _id: "b",
// imgurl: "../../../static/07.jpg",
// time: nowTime,
// message: e.message,
// types: e.types,
// tip: len
// };
// List.value.push(data)
// nextTick(() => {
// scrollToView.value = 'msg' + len
// })
// if (e.types == 1) {
// getimg.value.push(e.message)
// }
// })
uni.$on('inputs', (e) => {
getInput(e, user.uid, user.uimgurl, 0)
console.log(e);
})
// 接收消息
const getInput = (e, id, img, tip) => {
// tip=0表示自己发的。tip=1表示对方发的
// socket提交
// 文字或者地图
if (e.types == 0 || e.types == 3) {
sendSocket(e)
}
// 图片
if (e.types == 1) {
getimg.value.push(e.message)
// 提交图片处理
const uploadTask = uni.uploadFile({
url: 'http://localhost:3461/files/upload', //仅为示例,非真实的接口地址
filePath: e.message,
name: 'file',
formData: {
url: 'picture',
name: new Date().getTime() + user.uid + Math.ceil(Math.random() * 10),
},
success: (uploadFileRes) => {
// console.log(uploadFileRes);
let data = {
message: uploadFileRes.data,
types: e.types
}
sendSocket(data)
// let path = uploadFileRes.data
// img.value.push('http://localhost:3461/'+path)
// console.log(uploadFileRes.data);
},
});
uploadTask.onProgressUpdate((res) => {
// console.log('上传进度' + res.progress);
// console.log('已经上传的数据长度' + res.totalBytesSent);
// console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
// 测试条件,取消上传任务。
// if (res.progress > 50) {
// uploadTask.abort();
// }
});
}
// 音频
if (e.types == 2) {
// 提交音频处理
const uploadTask = uni.uploadFile({
url: 'http://localhost:3461/files/upload', //仅为示例,非真实的接口地址
filePath: e.message.voice,
name: 'file',
formData: {
url: 'voice',
name: new Date().getTime() + user.uid + Math.ceil(Math.random() * 10),
},
success: (uploadFileRes) => {
// console.log(uploadFileRes);
let data = {
// json转json字符串
message: JSON.stringify({
voice:uploadFileRes.data,
time:e.message.time
}),
types: e.types
}
sendSocket(data)
// let path = uploadFileRes.data
// img.value.push('http://localhost:3461/'+path)
// console.log(uploadFileRes.data);
},
});
uploadTask.onProgressUpdate((res) => {
// console.log('上传进度' + res.progress);
// console.log('已经上传的数据长度' + res.totalBytesSent);
// console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
// 测试条件,取消上传任务。
// if (res.progress > 50) {
// uploadTask.abort();
// }
});
}
// 前端处理
let len = List.value.length;
let nowTime = new Date()
// 时间间隔
let t = myfun.spaceTime(oldTime.value, nowTime)
if (t) {
oldTime.value = t
}
nowTime = t
// json字符串还原
if(e.types == 3){
e.message = JSON.parse(e.message)
}
let data = {
fromId: id,
imgurl: img,
time: nowTime,
message: e.message,
types: e.types,
id: len
};
List.value.push(data)
nextTick(() => {
scrollToView.value = 'msg' + len
})
}
// 聊天数据发送给服务端(socket)
const sendSocket = (e) => {
uni.request({
url: 'http://localhost:3461/wsb/insertMsg',
data: JSON.stringify({
msg: e.message,
types: e.types,
uid: user.uid,
fid: friend.fid
}),
method: 'POST',
success: (data) => {
let code = data.data.code
if (code == 200) {
// console.log("添加成功");
} else {
uni.showToast({
title: "服务器出错啦!",
icon: "none",
duration: 2000
})
}
}
})
// json字符串还原
if(e.types == 2){
e.message = JSON.parse(e.message)
}
uni.sendSocketMessage({
data: JSON.stringify({
message: e.message,
types: e.types,
uid: user.uid,
fid: friend.fid
})
});
}
// socket聊天数据接收
const receiveSocketMsg = () => {
uni.onSocketMessage(function(res) {
console.log('收到服务器内容123:' + res.data);
const msggs = JSON.parse(res.data)
if (msggs.from == friend.fid && msggs.tip==1) {
let len = List.value.length;
let nowTime = new Date()
// 时间间隔
let t = myfun.spaceTime(oldTime.value, nowTime)
if (t) {
oldTime.value = t
}
// 判断是否加ip
if (msggs.types == 1) {
msggs.message = 'http://localhost:3461' + msggs.message
}
if ( msggs.types == 2) {
msggs.message.voice = 'http://localhost:3461' + msggs.message.voice
}
nowTime = t
let data = {
fromId: msggs.from, //发送者的id
imgurl: friend.fimgurl,
time: nowTime,
message: msggs.message,
types: msggs.types,
id: len
};
List.value.push(data)
// 图片
if (msggs.types == 1) {
getimg.value.push(msggs.message)
}
nextTick(() => {
scrollToView.value = 'msg' + len
})
}
});
}
// 输入框的高度
uni.$on('heights', (e) => {
// console.log(e);
inputh.value = e.msg
// console.log(inputh .value);
goBottom()
})
// 滚动到底部
const goBottom = () => {
scrollToView.value = ''
nextTick(() => {
let len = List.value.length - 1
scrollToView.value = 'msg' + List.value[len].id
})
}
// 处理时间
const Datas = (data) => {
return myfun.dateTime(data)
}
// 返回上一页
const back = () => {
uni.navigateBack({
delta: 1
});
}
// 图片预览
const previewImg = (e) => {
let index = 0;
// 点击图片后通过for循环查找出第几张是该点击得图片
for (let i = 0; i < getimg.value.length; i++) {
if (getimg.value[i] == e) {
index = i;
}
}
// uni中的api,图片预览
uni.previewImage({
current: index, // 点击图片看第几张
urls: getimg.value,
longPressActions: {
itemList: ['发送给朋友', '保存图片', '收藏'],
success: function(data) {
console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
},
fail: function(err) {
console.log(err.errMsg);
}
}
});
}
// 音频播放
const playVoice = (e) => {
innerAudioContext.src = e;
innerAudioContext.play();
}
// 获取位置
const covers = (e) => {
let map = [{
latitude: e.latitude,
longitude: e.longitude,
iconPath: '../../../static/submit/dw1.png'
}]
return map
}
// 导航定位
const openLocations = (e) => {
uni.openLocation({
latitude: e.latitude,
longitude: e.longitude,
name: e.name,
address: e.address,
success: function() {
console.log('success');
}
});
}
</script>
<style lang="scss">
.chatroom {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.1);
.top-bar {
position: fixed;
z-index: 1001;
top: 0;
left: 0;
width: 100%;
height: 120rpx;
padding-top: var(--status-bar-height);
background: #fff;
border-bottom: 1rpx solid #ccc;
.top-bar-left {
float: left;
padding-left: 5rpx;
image {
margin-top: 10rpx;
width: 68rpx;
height: 88rpx;
border-radius: 16rpx;
}
}
.top-bar-center {
float: auto;
text-align: center;
.title {
font-size: 40rpx;
color: #000;
line-height: 120rpx;
}
}
}
}
.chat {
height: 100%;
.padbt {
width: 100%;
height: 40rpx;
}
.chat-main {
padding-left: 32rpx;
padding-right: 32rpx;
padding-top: 160rpx;
display: flex;
flex-direction: column;
}
.chat-ls {
.chat-time {
font-size: 24rpx;
color: rgba(39, 40, 50, 0.3);
line-height: 34rpx;
padding: 25rpx 0;
text-align: center;
}
.msg-m {
display: flex;
padding: 20rpx 0;
.user-img {
flex: none;
width: 80rpx;
height: 80rpx;
border-radius: 20rpx;
}
.massage {
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-color: #fff;
width: 460rpx;
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: 26rpx;
color: rgba(39, 40, 50, 0.4);
padding: 0rpx 24rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
}
.map {
padding-top: 8rpx;
width: 460rpx;
height: 190rpx;
}
}
.voice {
min-width: 80rpx;
max-width: 400rpx;
}
.voice-img {
width: 28rpx;
height: 36rpx;
}
}
.msg-left {
flex-direction: row;
.msg-text {
margin-left: 16rpx;
background: #fff;
border-radius: 0rpx 20rpx 20rpx 20rpx;
}
.msg-img {
margin-left: 16rpx;
}
.msg-map {
margin-left: 16rpx;
border-radius: 0rpx 20rpx 20rpx 20rpx;
}
.voice {
width: 200rpx;
text-align: left;
}
.voice-img {
width: 28rpx;
height: 36rpx;
padding-top: 4rpx;
}
}
.msg-right {
flex-direction: row-reverse;
.msg-text {
margin-right: 16rpx;
background: #fff260;
border-radius: 20rpx 0rpx 20rpx 20rpx;
}
.msg-img {
margin-right: 16rpx;
}
.msg-map {
margin-right: 16rpx;
border-radius: 20rpx 0rpx 20rpx 20rpx;
}
.voice {
width: 200rpx;
text-align: right;
}
.voice-img {
float: right;
transform: rotate(180deg);
width: 28rpx;
height: 36rpx;
padding-top: 4rpx;
}
}
}
}
</style>
到了这里,关于uniapp(vue3)+node.js+websocket(实现实时通信效果)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!