uniapp(vue3)+node.js+websocket(实现实时通信效果)

这篇具有很好参考价值的文章主要介绍了uniapp(vue3)+node.js+websocket(实现实时通信效果)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章目录

    • 概要
    • 整体架构流程
    • 技术名词解释
    • 技术细节
    • 小结

概要

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
								})
							}
						}
					})
				}
			}
		});
	}
效果:
uniapp vue3 websocket,uni-app,node.js,websocket,javascript,网络协议,网络,微信小程序

如果还没有打开就会是未读消息,消息数加一,就在我们的头像右上角,大家可以看到小红数,当打开聊天框后小红数才会消失

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
				})
			}

		});
	}
表情效果:

uniapp vue3 websocket,uni-app,node.js,websocket,javascript,网络协议,网络,微信小程序

表情可以看作是线上文字交流的重要补充。相较于面对面的沟通,人们在线上文字对话时较难感知对方的状态或情绪,而发送表情刚好可以弥补这一缺憾。

语音效果:

uniapp vue3 websocket,uni-app,node.js,websocket,javascript,网络协议,网络,微信小程序

语音可以帮助我们快速回复对方,在发语音时,我们可以通过声音来表达自己的想法和情感,与对方进行交流和互动。

完整代码

完成效果:

uniapp vue3 websocket,uni-app,node.js,websocket,javascript,网络协议,网络,微信小程序

服务端

/**
 * 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模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 实时通信应用的开发:Vue.js、Spring Boot 和 WebSocket 整合实践

    目录 1. 什么是webSocket  2. webSocket可以用来做什么? 3. webSocket协议 4. 服务器端 5. 客户端 6. 测试通讯 WebSocket 是一种在单个 TCP连接 上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允 许服务端主动向客户端推送数据 。在WebSocket API中,浏览

    2024年02月11日
    浏览(42)
  • vue和node使用websocket实现数据推送,实时聊天

    需求:node做后端根据websocket,连接数据库,数据库的字段改变后,前端不用刷新页面也能更新到数据,前端也可以发送消息给后端,后端接受后把前端消息做处理再推送给前端展示 使用node ./app.js运行项目 在需要使用websocket连接的页面引入 默认如下: id为243 在数据库改为

    2024年02月15日
    浏览(34)
  • 使用vue3简单实现WebSocket通信

    关于WebSocket通信的简单介绍: 握手阶段:在建立WebSocket连接之前,客户端需要发送一个HTTP请求到服务器,请求升级为WebSocket协议。这个过程称为握手(Handshake)。如果服务器支持WebSocket协议,它将返回带有特定标头的HTTP响应,表示握手成功。 建立连接:客户端收到服务器的

    2024年02月16日
    浏览(27)
  • uniapp实现红包动画效果(vue3)

    首先安装CSS动画库animate.css依赖 打开main.ts文件引入 这两张图片放入static文件夹下 用到的图片red1.png 用到的图片red2.png 红包整体主要分三部分 红包头部 中部 底部 使用uni.createAnimation()创建动画实例并进行相关操作具体查看官方文档 除了红包底部 头部和中部需要定位

    2024年02月12日
    浏览(35)
  • 【你的第一个socket应用】Vue3+Node实现一个WebSocket即时通讯聊天室

    这篇文章主要是用WebSocket技术实现一个 即时通讯聊天室 ,首先先要了解为什么使用WebSocket而不是普通的HTTP协议,如果使用HTTP协议它是下面这种情况: 我发送一条消息,发送一个发送消息的请求;* 一直轮询接收别人发送的消息,不管有没有发送都要定时去调用接口。这里明

    2023年04月20日
    浏览(45)
  • 使用 vue-3-socket.io 插件以及node.js实现实时聊天(1)

     这篇文章使用选项式API的写法,以实现群聊和私聊为主 客户端自然是对应使用vue3框架,服务端使用node.js配合express、http、socket.io、file等库来实现,具体如下: 1、下载所需的依赖 2、做socket客户端配置 注:\\\"http://localhost:3000\\\",该地址端口是对应后面配置服务端时所开放的端

    2024年02月05日
    浏览(35)
  • 【vue3】js + css 实现 视频框选放大:局部细节放大、放大镜效果

    实现鼠标框选区域放大显示。 需求1:放大 按住鼠标左键不放 ——》向右侧拖动,框选出需要放大的区域后 ——》松开鼠标 ——》框选区域放大显示 需求2:还原 按住鼠标左键不放 ——》向左侧拖动,框选出随意大小的区域后 ——》松开鼠标 ——》视图显示大小还原 需求

    2024年02月03日
    浏览(41)
  • 超详细--vue3中使用socket.io-client + nodejs使用socket.io 实现实时通信

    第一步:安装插件 第二步:组件中引入使用 第一步:安装插件 第二步:在文件中引入使用

    2024年02月13日
    浏览(28)
  • uniapp使用vue3和ts开发小程序自定义tab栏,实现自定义凸出tabbar效果

    要实现自定义的tabbar效果,可以使用自定义tab覆盖主tab来实现,当程序启动或者从后台显示在前台时隐藏自带的tab来实现。自定义一个tab组件,然后在里面实现自定义的逻辑。 组件中所使用的组件api可以看:Tabbar 底部导航栏 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-

    2024年02月04日
    浏览(31)
  • Spring Boot整合WebSocket实现实时通信,前端实时通信,前后端实时通信

    实时通信在现代Web应用中扮演着越来越重要的角色,无论是在线聊天、股票价格更新还是实时通知,WebSocket都是实现这些功能的关键技术之一。Spring Boot作为一个简化企业级应用开发的框架,其对WebSocket的支持也非常友好。本文将详细介绍如何在Spring Boot中整合WebSocket,实现一

    2024年04月27日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包