使用LeanCloud平台的即时通讯

<template> <div class="chat"> <div class="userList"> <ul> <li v-for="item in userList" :class="{ active: item === adverse }" :key="item" @click="selectUser(item)">{{ item }}</li> </ul> </div> <div class="instant-messaging"> <h3>{{ adverse }}</h3> <ul v-show="newMessage.length !== 0" ref="scrollContainer" id="scrollContainer" class="scroll-container"> <li v-for="item in newMessage" :key="item" class="message-item" :style="`justify-content: ${item.from !== creator ? 'flex-start' : 'flex-end'};`"> <div v-if="item.from !== creator" class="message-content"> <div class="user"> <img :src="'https://img0.baidu.com/it/u=2226630510,461838410&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=521'" alt="" /> </div> <div class="message image" :style="'padding: 6px;'" v-if="item.content._lctype === -2"> <img :src="item.content._lcfile.url" alt="" /> </div> <div class="message" v-if="item.content._lctype === -1">{{ item.content._lctext }}</div> </div> <div v-else class="message-content"> <div class="message image" :style="'padding: 6px;'" v-if="item.content._lctype === -2"> <img :src="item.content._lcfile.url" alt="" /> </div> <div class="message" v-if="item.content._lctype === -1">{{ item.content._lctext }}</div> <div class="user"> <img :src="'https://img1.baidu.com/it/u=3622150954,2575811681&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500'" alt="" /> </div> </div> </li> </ul> <ul v-show="newMessage.length === 0"> <li>暂无消息</li> </ul> <div class="message-operation"> <!-- <el-button type="primary" @click="moreMessage">更多</el-button> --> <el-upload v-model:file-list="fileList" ref="uploadRef" class="upload-demo" multiple :limit="3" :auto-upload="false" :show-file-list="false" :accept="'image/*'"> <el-button :icon="Picture" /> </el-upload> <el-input class="message-input" v-model="messageValue" @keyup.enter="sendMessage" style="width: 240px" placeholder="" /> <el-button type="primary" @click="sendMessage">发送</el-button> </div> </div> </div> </template> <script setup> import * as IM from 'leancloud-realtime' import AV from 'leancloud-storage' import initPlugin from 'leancloud-realtime-plugin-typed-messages' import { onMounted, ref, watch, onBeforeUnmount } from 'vue' import { ElMessage } from 'element-plus' import { Picture } from '@element-plus/icons-vue' import axios from 'axios' const props = defineProps({ // 自己的 id ownId: { type: String, default: '' }, // 对方的 id adverseId: { type: String, default: '' }, // 聊天室名称 chatsName: { type: String, default: '' }, }) const { Realtime, TextMessage, Event } = IM const { TypedMessagesPlugin, ImageMessage } = initPlugin(AV, IM) let realtime; const newMessage = ref([]) const creator = ref('') const adverse = ref('') const messageValue = ref('') const fileList = ref([]) const uploadRef = ref(null) const scrollContainer = ref(null) // 监听文件上传 watch( () => fileList.value.length, () => { console.log(fileList.value) fileList.value.length !== 0 && sendMessage() } ) // 发送消息 const sendMessage = () => { console.log(messageValue.value === '' && fileList.value.length === 0) if (messageValue.value === '' && fileList.value.length === 0) { ElMessage({ message: '不能发送空消息!', type: 'warning' }) return } /** * 创建一个 IMClient 实例 */ // 1、Tom 用自己的名字作为 clientId 来登录即时通讯服务 realtime .createIMClient(props.ownId) .then(function (own) { // 成功登录 console.log('登录成功', own) // 创建与 Jerry 之间的对话 own.createConversation({ // tom 是一个 IMClient 实例 // 指定对话的成员除了当前用户 Tom(SDK 会默认把当前用户当做对话成员)之外,还有 Jerry members: [props.adverseId], // 对话名称 name: props.chatsName, unique: true }).then(function (conversation) { // 创建成功 console.log('创建成功', conversation) // 发送一条文本消息 if (messageValue.value !== '') { conversation .send(new TextMessage(messageValue.value)) .then(function (message) { console.log('发送成功!') createUser_Jerry() messageValue.value = '' }) .catch(console.error) } if (fileList.value.length !== 0) { var file = new AV.File('avatar.jpg', fileList.value[0].raw) file .save() .then(function () { var message = new ImageMessage(file) message.setText('本地图片') message.setAttributes({ location: '武汉' }) return conversation.send(message) }) .then(function () { console.log('发送成功') createUser_Jerry() fileList.value = [] }) .catch(console.error.bind(console)) } }) }) .catch(console.error) } const createUser_Jerry = () => { // Jerry 登录 realtime .createIMClient(props.ownId) .then(function (own) { // 成功登录 console.log('登录成功', own) creator.value = own.id // 确保 Jerry 已加入对话 own.createConversation({ members: [props.adverseId], name: props.chatsName, unique: true }).then(function (conversation) { // 创建成功 console.log('创建成功', conversation) adverse.value = conversation.members.find((item) => item !== conversation.creator) // 当前用户被添加至某个对话 own.on(Event.INVITED, function invitedEventHandler(payload, conversation) { console.log(payload.invitedBy, conversation.id) }) // 当前用户收到了某一条消息,可以通过响应 Event.MESSAGE 这一事件来处理。 own.on(Event.MESSAGE, function (message, conversation) { // newMessage.value.push(message.text) console.log('收到新消息:' + message.text, conversation) getChatRecord(conversation) }) getChatRecord(conversation) }) }) .catch(console.error) } let messageIterator // 获取聊天记录 const getChatRecord = (conversation) => { // conversation // .queryMessages({ // limit: 10, // limit 取值范围 1~100,默认 20 // }) // .then(function (messages) { // // 最新的十条消息,按时间增序排列 // newMessage.value = messages // }) // .catch(console.error.bind(console)); // JS SDK 通过迭代器隐藏了翻页的实现细节,开发者通过不断的调用 next 方法即可获得后续数据。 // 创建一个迭代器,每次获取 10 条历史消息 messageIterator = conversation.createMessagesIterator({ limit: 50 }) // 第一次调用 next 方法,获得前 10 条消息,还有更多消息,done 为 false messageIterator .next() .then(function (result) { // result: { // value: [message1, ..., message10], // done: false, // } console.log(result) newMessage.value = result.value scrollContainer.value.scrollTop = scrollContainer.value.scrollHeight }) .catch(console.error.bind(console)) } // 更多消息 const moreMessage = () => { // 第二次调用 next 方法,获得第 11~20 条消息,还有更多消息,done 为 false // 迭代器内部会记录起始消息的数据,无需开发者显示指定 messageIterator .next() .then(function (result) { // result: { // value: [message21, ..., message30], // done: true, // } if (result.value.length === 0) { ElMessage.warning('没有更多消息了') return } // newMessage.value = [...result.value, ...newMessage.value] newMessage.value = result.value.concat(newMessage.value) }) .catch(console.error.bind(console)) } let isScrollLocked = true // 滚动事件 const handleScroll = () => { if (!isScrollLocked && isNearTop(scrollContainer.value)) { isScrollLocked = true // 锁定滚动条位置 const ulContainer = document.getElementById('scrollContainer') console.log(ulContainer.scrollHeight) setTimeout(() => { moreMessage() isScrollLocked = false }, 1000) } else { setTimeout(() => { isScrollLocked = false }, 1000); } } /* 节流 */ const throttle = (func, delay) => { let time = null return function () { let args = Array.from(arguments) if (time === null) { time = setTimeout(() => { func(...args) clearTimeout(time) time = null }, delay) } } } // 是否到达顶部 const isNearTop = (scrollContainer) => { const threshold = 50 // 可调整的阈值,距离底部多少像素时触发加载 return scrollContainer.scrollTop <= threshold } // 延迟一段时间后再获取滚动高度 const checkAndSetScrollTop = () => { const ulContainer = document.getElementById('scrollContainer') // 确保滚动高度不为零 if (ulContainer.scrollHeight !== 0) { // 将滚动条设置到最底部 ulContainer.scrollTop = ulContainer.scrollHeight } else { // 如果滚动高度仍为0,再延迟几秒重新检查 setTimeout(checkAndSetScrollTop, 500) // 这里的延迟时间可以根据实际情况调整 } } const userList = ref([]) // 获取会话 const getConversation = () => { axios({ method: 'get', url: `/1.2/rtm/conversations?limit=10&where={"c": "${props.ownId}"}`, headers: { 'X-LC-Id': 'NLblIbY4gEKenESSb7Q3vY9Y-gzGzoHsz', 'X-LC-Key': 'l1JvznaAgLvkGumBdiXDYQ6q,master', 'Content-Type': 'application/json' } }) .then(function (response) { console.log(response.data); userList.value = response.data.results.map(item => { return item.m.find(v => v !== item.c) }) console.log(userList.value); }); } const emit = defineEmits(['selectUser']) // 选择用户 const selectUser = (user) => { emit('selectUser', user) } // 监听props.adverseId watch(() => props.adverseId, () => { createUser_Jerry() getConversation() getUnreader() } ) // 获取未读消息 const getUnreader = () => { axios({ method: 'get', url: `/1.2/rtm/clients/${props.ownId}/unread-count
上一篇:webpack如何实现懒加载


下一篇:Tax4Fun2分析:基于16S数据预测微生物群落的功能(R语言一句代码搞定)-数据和代码获取:请查看主页个人信息!!!