使用LeanCloud平台的即时通讯

LeanCloud 是领先的 Serverless 云服务,为产品开发提供强有力的后端支持,旨在帮助开发者降低研发、运营维护等阶段投入的精力和成本。 LeanCloud 整合了各项服务,让开发者能够聚焦在核心业务上,为客户创造更多价值。

*即时通讯

LeanCloud地址

效果图

在这里插入图片描述

安装

npm install leancloud-realtime leancloud-realtime-plugin-typed-messages leancloud-storage --save

简单封装ChatComponent.vue

<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({// 自己的 idownId: {type: String,default: ''},// 对方的 idadverseId: {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 会默认把当前用户当做对话成员)之外,还有 Jerrymembers: [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 为 falsemessageIterator.next().then(function (result) {// result: {//   value: [message1, ..., message10],//   done: false,// }console.log(result)newMessage.value = result.valuescrollContainer.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 = nullreturn 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`,headers: {'X-LC-Id': 'NLblIbY4gEKenESSb7Q3vY9Y-gzGzoHsz','X-LC-Key': 'l1JvznaAgLvkGumBdiXDYQ6q,master','Content-Type': 'application/json'}}).then(function (response) {console.log(response.data);if (response.data.unread > 0) {ElMessage.warning('有新消息')}});
}onMounted(() => {realtime = new Realtime({appId: 'NLblIbY4gEKenESSb7Q3vY9Y-gzGzoHsz',appKey: 'pVpG3Q8DWAnWDWUquOb5cBu0',server: 'https://nlbliby4.lc-cn-n1-shared.com',// 初始化即时通讯服务时需要指定富媒体消息插件plugins: [TypedMessagesPlugin]})localStorage.setItem('debug', 'LC*')AV.init({appId: 'NLblIbY4gEKenESSb7Q3vY9Y-gzGzoHsz',appKey: 'pVpG3Q8DWAnWDWUquOb5cBu0',serverURL: 'https://nlbliby4.lc-cn-n1-shared.com'})createUser_Jerry()getConversation()getUnreader()checkAndSetScrollTop() // 延迟一段时间后再获取滚动高度scrollContainer.value.addEventListener('scroll', throttle(handleScroll, 1000))
})onBeforeUnmount(() => {scrollContainer.value.removeEventListener('scroll', handleScroll)
})
</script><style lang="scss" scoped>
* {ul,li {list-style: none;padding: 0;margin: 0;}
}.chat {display: flex;.userList {border: 1px solid #e3e3e3;width: 16%;ul {li {line-height: 36px;background: #e3e3e3;padding: 0 10px;margin-bottom: 1px;cursor: pointer;}li:hover{background: #cacaca;}.active{background: #c1c1c1;}}}.instant-messaging {flex: 1;background: #f1f1f1;padding: 20px;h3 {text-align: center;}.scroll-container {height: 580px;overflow-y: auto;&::-webkit-scrollbar {/*滚动条整体样式*/width: 10px;/*高宽分别对应横竖滚动条的尺寸*/height: 10px;}&::-webkit-scrollbar-thumb {/*滚动条里面小方块*/border-radius: 10px;background: #ccc;box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);}.message-item {display: flex;margin-bottom: 10px;.message-content {display: flex;align-items: center;.user {width: 36px;height: 36px;margin-right: 10px;border-radius: 50px;img {width: 100%;height: 100%;}}.message {line-height: 36px;background: #fff;padding: 0 6px;margin-right: 10px;display: flex;justify-content: center;}.image {max-width: 100px;height: 52px;img {width: 100%;height: 100%;}}}}}.message-operation {display: flex;justify-content: flex-end;.message-input {margin: 0 20px;}}}
}
</style>

使用组件

<template><div><ChatComponent :ownId="ownId" :adverseId="adverseId" :chatsName="chatsName" @selectUser="selectUser" /></div>
</template><script setup>
import ChatComponent from '@/components/ChatComponent.vue'
import { ref } from 'vue'// const ownId = ref('goto_w')
// const adverseId = ref('tom')
// const chatsName = ref('goto_w  & tom')// const ownId = ref('红红')
// const adverseId = ref('熊熊')
// const chatsName = ref('红红  & 熊熊')const ownId = ref('goto_w')
const adverseId = ref('M')
const chatsName = ref('goto_w & M')const selectUser = (user) => {adverseId.value = user
}</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/337725.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5月29日-shell复习

一.Shell概述 1&#xff09;Linux提供的Shell解析器有&#xff1a;sudo cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/tcsh /bin/csh 2&#xff09;bash和sh的关系 cd /bin ll | grep bash 或者使用&#xff1a;ls -l /bin/ | grep bash 3&#xff0…

深入pandas:数据分析

目录 前言 第一点&#xff1a;导入模块 第二点&#xff1a;准备数据 第三点&#xff1a;简单的分析数据 第四点&#xff1a;【重点】数据透支 总结 前言 在数据分析与挖掘的领域&#xff0c;了解如何使用工具和方法来探索数据是至关重要的。本文将探讨如何利用Python中的…

MAB规范(1):概览介绍

前言 MATLAB的MAAB&#xff08;MathWorks Automotive Advisory Board&#xff09;建模规范是一套由MathWorks主导的建模指南&#xff0c;旨在提高基于Simulink和Stateflow进行建模的代码质量、可读性、可维护性和可重用性。这些规范最初是由汽车行业的主要厂商共同制定的&…

如何使用宝塔面板搭建Tipask问答社区网站并发布公网远程访问

文章目录 前言1.Tipask网站搭建1.1 Tipask网站下载和安装1.2 Tipask网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3 Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试4.结语 前…

FreeRTOS基础(四):静态创建任务

上一篇博客&#xff0c;我们讲解了FreeRTOS中如何动态创建任务&#xff0c;那么这一讲&#xff0c;我们从实战出发&#xff0c;规范我们在FreeRTOS下的编码风格&#xff0c;掌握静态创建任务的编码风格&#xff0c;达到实战应用&#xff01; 目录 一、空闲任务和空闲任务钩子…

MT8781安卓核心板_MTK联发科Helio G99核心板规格参数

MT8781安卓核心板采用先进的台积电6纳米级芯片生产工艺&#xff0c;配备高性能Arm Cortex-A76处理器和Arm Mali G57 GPU&#xff0c;加上LPDDR4X内存和UFS 2.2存储&#xff0c;在处理速度和数据访问速度上都有着出色的表现。 MT8781还支持120Hz显示器&#xff0c;无需额外的DSC…

TK防关联引流系统:全球TikTok多账号运营的神器

在TikTok的生态中&#xff0c;高效运营多个账号已成为品牌全球推广的必经之路。为此&#xff0c;TK防关联引流系统应运而生&#xff0c;它是一款专为TikTok设计的效率神器&#xff0c;助您迅速搭建并管理全球多账号矩阵。该系统由先进的“防关联智能终端”硬件和智能的“TK防关…

随身wifi网络卡顿怎么解决?随身WiFi哪个牌子的最好用?排名第一名的随身WiFi!

对于随身wifi靠不靠谱这个问题&#xff0c;网上一直存在争议。很多人的随身wifi网速不稳定&#xff0c;信号看着满格就是上不了网。关于随身wifi卡顿到底该怎么解决呢&#xff1f; 1.如果是设备网络在一个地方上网速度很快&#xff0c;换一个地方网络就不行了&#xff0c;很可能…

常用中间件各版本下载

常用中间件下载地址 前言分布式中间件负载均衡中间件缓存中间件数据库中间件其他中间件1、Maven下载地址2、Git下载地址2、JDK下载地址3、MySQL下载地址4、Redis下载地址5、Nacos下载地址6、Tomcat下载地址7、Nginx下载地址8、RocketMQ下载地址8、RabbitMQ下载地址8、Erlang下载…

新设立湖北投资管理公司流程和要求

在湖北投资管理企业进行注册时&#xff0c;需要准备一系列的材料并按照一定的流程进行办理。本文将从注册材料及注册流程两方面来介绍&#xff0c;帮助您了解注册投资管理企业的步骤和所需的具体材料。详情致电咨询我或者来公司面谈。 新注册材料要求: 企业名称申请书:要求提供…

Day 9:2829. k-avoiding 数组的最小总和

Leetcode 2829. k-avoiding 数组的最小总和 给你两个整数 n 和 k 。 对于一个由 不同 正整数组成的数组&#xff0c;如果其中不存在任何求和等于 k 的不同元素对&#xff0c;则称其为 k-avoiding 数组。 返回长度为 n 的 k-avoiding 数组的可能的最小总和。 n 个不同正整数的最…

树形结构-CRUD接口

先看一下效果&#xff1a;整体的效果 新增效果 --默认值是 default 修改效果 - 大致效果如上 --------------------------------------------------------------------------------------------------------------------------------- 下面讲解代码如何实现的 根据你使用…

Selenium+Java 环境搭建

selenium 介绍 Selenium 是 web 应用中基于 UI 的自动化测试框架&#xff0c;支持多平台、多浏览器、多语言。 早期的 selenium RC 已经被现在的 webDriver 所替代&#xff0c;可以简单的理解为selenium1.0webdriver 构成 现在的 Selenium2.0 。现在我们说起 selenium &#xf…

AI大模型探索之路-实战篇12: 构建互动式Agent智能数据分析平台:实现多轮对话控制

系列篇章&#x1f4a5; AI大模型探索之路-实战篇4&#xff1a;深入DB-GPT数据应用开发框架调研 AI大模型探索之路-实战篇5&#xff1a;探索Open Interpreter开放代码解释器调研 AI大模型探索之路-实战篇6&#xff1a;掌握Function Calling的详细流程 AI大模型探索之路-实战篇7…

【机器学习300问】106、Inception网络结构如何设计的?这么设计的目的是什么?

谷歌的Inception网络&#xff0c;也被称为GoogLeNet&#xff0c;是Google在2014年推出的一种深度卷积神经网络&#xff08;CNN&#xff09;模型&#xff0c;在这之前的AlexNet、VGG等结构都是通过增大网络的深度&#xff08;层数&#xff09;来获得更好的训练效果&#xff0c;但…

vue3简单快速实现主题切换功能

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《vue3实战》 目录 内容概要 实现步骤 1.定义不同主题的css样式变量 2.入口main.ts中引入这个样式文件 3.主题样式css变量引用 4.设置默认主题样式 5.实现点击按钮主题切换 总结 最近发现了一个巨牛的人工智…

JS-Lodash工具库

文档&#xff1a;Lodash Documentation orderBy函数&#xff1a;根据条件进行排序 注&#xff1a;第一个是要排序的数组&#xff0c;第二个是根据什么字段进行排序&#xff0c;第三个是排序的方式&#xff08;desc倒序&#xff09; 安装方式&#xff1a;Lodash npm i lodash…

python判断文件是否存在

import os test_path "/Users/yxk/Desktop/test/GrayScale.tif" if(os.path.exists(test_path)):print(文件存在&#xff01;&#xff01;&#xff01;&#xff01;) else:print("文件不存在&#xff01;&#xff01;&#xff01;&#xff01;")结果如下 …

ABAP 借助公司封装的钉钉URL,封装的RFC给钉钉发送消息

FUNCTION ZRFC_BC_SMSSEND_DINGTALK. *"---------------------------------------------------------------------- *"*"本地接口&#xff1a; *" IMPORTING *" VALUE(DESTUSRID) TYPE CHAR255 *" VALUE(CONTENT) TYPE CHAR255 *&quo…

Linux 的权限

目录 Linux 的用户 root 用户 和 普通用户 如何新建普通用户&#xff1f; 如何切换用户&#xff1f; 一开始是以 root 用户登录&#xff1a; 一开始以普通用户登录&#xff1a; 如何删除用户&#xff1f; Linux文件权限 什么是读权限&#xff08; r &#xff09;&#…