IM 即时通讯实战:环信Web IM极速集成

news/2024/10/18 18:23:20/

前置技能

  • Node.js 环境已搭建。
  • npm 包管理工具的基本使用。
  • Vue2 或者 Vue3 框架基本掌握或使用。

学习目标

  • 项目中集成 IM 即时通讯实战
  • 利用环信 IM Web SDK 快速实现在 Vue.js 中发送出一条 Hello World!

一、了解环信 IM

  1. 什么是环信 IM?

    环信即时通讯为开发者提供高可靠、低时延、高并发、安全、全球化的通信云服务,支持单聊、群聊、聊天室。提供多平台 SDK 支持,包括:Android、iOS、Web;同时,提供 EaseIM 和 EaseIMKit 以及服务端 REST API,帮助开发者快速构建端到端通信的场景。

  2. 学习完环信 WebIM 之后可以干嘛?

    可以在任意 Web 应用中极速集成搭建即时通讯功能,无论是自己搭建 IM 应用,还是实现产品需求均可以灵活集成进入到自己的项目之中。

二、环信 WebIM 实现通讯的基本流程

前置准备

  1. 有效的开发者 AppKey。 ( 注册环信)(注册参考文档)
  2. 使用 Vue-cli 创建一个空白项目,或已经具备已有待集成项目(此篇文章以 Vue3 为示例,Vue2 同样可以参考此文章)。
  3. 在项目中使用 npm 或者 yarn 安装环信 WebSDK 包,easemob-websdk
  4. 下载环信官方 Vue3-Demo

我们开始

初期配置

在确保已进行 npm install easemob-websdk 安装了环信 SDK 包,并已经下载了 Vue3 官方 Demo,将项目中的 IM 文件拖入自己的项目中。

此文件共两个功能:

  • 引入环信 WebIM-SDK
  • 将引入的 SDK 进行实例化

在这里插入图片描述

DEFAULT_APPKEY修改为自己已注册的 Appkey。

配置监听

<script setup>
import { EaseChatClient } from '@/IM/initwebsdk'
/* SDK连接 相关监听 */
EaseChatClient.addEventHandler('connection', {onConnected: () => {}, //与环信服务器建联成功回调。onDisconnected: () => {}, //与环信服务器断开成功回调。onOnline: () => {}, // 本机网络连接成功。onOffline: () => {},// 本机网络掉线。onError: (error) => {}, //SDK Error 回调
})
/* 好友关系相关监听 */
EaseChatClient.addEventHandler('friendListen', {// 收到好友邀请触发此方法。onContactInvited: (data) => {},// 联系人被删除时触发此方法。onContactDeleted: (data) => {},// 新增联系人会触发此方法。onContactAdded: (data) => {},// 好友请求被拒绝时触发此方法。onContactRefuse: (data) => {},// 好友请求被同意时触发此方法。onContactAgreed: (data) => {}
})
/* message 相关监听 */
EaseChatClient.addEventHandler('messageListen', {onTextMessage: function (message) {}, // 收到文本消息。onEmojiMessage: function (message) {}, // 收到表情消息。onImageMessage: function (message) {}, // 收到图片消息。onCmdMessage: function (message) {}, // 收到命令消息。onAudioMessage: function (message) {}, // 收到音频消息。onLocationMessage: function (message) {}, // 收到位置消息。onFileMessage: function (message) {}, // 收到文件消息。onCustomMessage: function (message) {}, // 收到自定义消息。onVideoMessage: function (message) {}, // 收到视频消息。onRecallMessage: function (message) {}, // 收到消息撤回回执。
})
</script>

创建测试 ID

在这里插入图片描述

登录环信

这一步是所有后续操作的第一步

<script setup>
import { EaseChatClient } from '@/IM/initwebsdk'
const loginValue = reactive({user: '', //你的测试环信IDpassword: '' //你的测试环信ID密码
})
//登录接口调用
const loginIM = async () => {try {await EaseChatClient.open({user: loginValue.username.toLowerCase(),pwd: loginValue.password.toLowerCase()});} catch (error) {console.log('>>>>登录失败', error);}
}
</script>

紧接着是开始聊天部分。

好友关系

完成这个功能 需要将该项目开启两个页面,一个申请,一个接收,这样才能看到效果

两种方式:手动关联一个好友,第二种再创建一个测试 ID 之后,调用 SDK 添加好友。

方式一:测试时最简单的方式,手动关联好友

  1. 在管理后台中手动再创建一个 ID
    image.png

2.并手动将新创建的 ID 关联为好友。
在这里插入图片描述

方式二:开发时调用 SDK 接口添加好友

//申请添加好友
const applyAddFriends = () => {EaseChatClient.addContact(targetId, '我想加你为好友!');
};
//接收方登录将会触发
EaseChatClient.addEventHandler('friendListen', {// 收到好友邀请触发此方法。onContactInvited: (data) => {//同意申请EaseChatClient.acceptContactInvite(data.from);//拒绝申请EaseChatClient.declineContactInvite(data.from);},
});

进入页面获取好友列表并自行渲染。

<script setup>
//获取好友列表
const friendListData = reactive({})
const { data } = await EaseChatClient.getContacts()
data.length > 0 &&data.map(item => (friendListData[item] = { hxId: item }))
</script>

收发消息

完成这个功能 需要将该项目开启两个页面,一个发送,一个接收,这样才能看到效果

发送方发送一条文本消息:

<script setup>
const props = defineProps({nowPickInfo: {type: Object,required: true,default: () => ({})}
})
const { nowPickInfo } = toRefs(props)
const { ALL_MESSAGE_TYPE, CHAT_TYPE } = messageType
//发送文本内容
const textContent = ref('')
const sendTextMessage = _.debounce(async () => {//如果输入框全部为空格同样拒绝发送if (textContent.value.match(/^\s*$/)) returnconst msgOptions = {id: nowPickInfo.value.id, //要发送的目标IDchatType: nowPickInfo.value.chatType,msg: textContent.value,}textContent.value = '' //发送后清空输入框try {await store.dispatch('sendShowTypeMessage', { msgType: ALL_MESSAGE_TYPE.TEXT, msgOptions })} catch (error) {console.log('>>>>>>>发送失败+++++++', error)}
}, 50)
</script>

接收方接收消息

/* message 相关监听 */
EaseChatClient.addEventHandler('messageListen', {onTextMessage: function (message) {console.log('>>>>收到文本消息');pushNewMessage(message); //在缓存中Push一条新消息。}, // 收到文本消息。
});

缓存的消息结构示例

messageList:{//以好友的ID为KEY,如果获取则直接messageList[friendId]取到对应的消息。friendId:[{chatType:"singleChat", //聊天类型 单聊或者群聊ext:{}, //消息扩展from:friendId, //消息来源IDid:"1111864344594875684", //消息的唯一IDmsg:"Hello World!",//消息内容time:1676440891009,//消息发送时间to:myId,//发送目标IDtype:"txt" //消息来源},{chatType:"singleChat",ext:{},from:friendId,id:"1111864344594875684",msg:"Hello World2!",time:1676440891009,to:myId,type:"txt"}],friendId2:[{chatType:"singleChat",ext:{},from:friendId,id:"1111864344594875684",msg:"Hello World!",time:1676440891009,to:myId,type:"txt"},]
}

渲染消息列表

<script setup>
import { reactive, ref, computed, toRefs } from 'vue'
//获取其id对应的消息内容
const messageData = computed(() => {//如果Message.messageList中不存在的话调用拉取漫游取一下历史消息return nowPickInfo.value.id && store.state.Message.messageList[nowPickInfo.value.id] || fechHistoryMessage('fistLoad')()
})
<template><div><div class="messageList_box" v-for="(msgBody, index) in messageData" :key="msgBody.id"><div v-if="!msgBody.isRecall && msgBody.type !== ALL_MESSAGE_TYPE.INFORM" class="message_box_item":style="{ flexDirection: (isMyself(msgBody) ? 'row-reverse' : 'row') }"><div class="message_item_time">{{ handleMsgTimeShow(msgBody.time, index) || '' }}</div><el-avatar class="message_item_avator":src="isMyself(msgBody) ? loginUserInfo.avatarurl : otherUserInfo(msgBody.from).avatarurl || defaultAvatar"></el-avatar><el-dropdown class="message_box_content":class="[isMyself(msgBody) ? 'message_box_content_mine' : 'message_box_content_other']"trigger="contextmenu" placement="bottom-end"><!-- 文本类型消息 --><p style="padding: 10px" v-if="msgBody.type === ALL_MESSAGE_TYPE.TEXT">{{ msgBody.msg }}</p><!-- 图片类型消息 --><!-- <div> --><el-image v-if="msgBody.type === ALL_MESSAGE_TYPE.IMAGE" style="border-radius:5px;":src="msgBody.thumb" :preview-src-list="[msgBody.url]" :initial-index="1" fit="cover" /><!-- </div> --><!-- 语音类型消息 --><div :class="['message_box_content_audio', isMyself(msgBody) ? 'message_box_content_audio_mine' : 'message_box_content_audio_other']"v-if="msgBody.type === ALL_MESSAGE_TYPE.AUDIO" @click="startplayAudio(msgBody, index)":style="`width:${msgBody.length * 10}px`"><span class="audio_length_text">{{ msgBody.length }}′′</span><div :class="[isMyself(msgBody) ? 'play_audio_icon_mine' : 'play_audio_icon_other', audioPlayStatus.playIndex === index && 'start_play_audio']"style=" background-size: 100% 100%;"></div></div><div v-if="msgBody.type === ALL_MESSAGE_TYPE.LOCAL"><p style="padding: 10px">[暂不支持位置消息展示]</p></div><!-- 文件类型消息 --><div v-if="msgBody.type === ALL_MESSAGE_TYPE.FILE" class="message_box_content_file"><div class="file_text_box"><div class="file_name">{{ msgBody.filename }}</div><div class="file_size">{{ fileSizeFormat(msgBody.file_length) }}</div><a class="file_download" :href="msgBody.url" download>点击下载</a></div><span class="iconfont icon-wenjian"></span></div><!-- 自定义类型消息 --><div v-if="msgBody.type === ALL_MESSAGE_TYPE.CUSTOM" class="message_box_content_custom"><template v-if="msgBody.customEvent && CUSTOM_TYPE[msgBody.customEvent]"><div class="user_card"><div class="user_card_main"><!-- 头像 --><el-avatar shape="circle" :size="50":src="msgBody.customExts && msgBody.customExts.avatarurl || msgBody.customExts.avatar || defaultAvatar"fit="cover" /><!-- 昵称 --><span class="nickname">{{ msgBody.customExts && msgBody.customExts.nickname ||msgBody.customExts.uid}}</span></div><el-divider style="margin:5px 0;  border-top:1px solid black;" /><p style="font-size: 8px;">个人名片</p></div></template></div><template #dropdown><el-dropdown-menu><el-dropdown-item v-if="msgBody.type === ALL_MESSAGE_TYPE.TEXT && isSupported"@click="copyTextMessages(msgBody.msg)">复制</el-dropdown-item><el-dropdown-item v-if="isMyself(msgBody)" @click="recallMessage(msgBody)">撤回</el-dropdown-item><el-dropdown-item @click="deleteMessage(msgBody)">删除</el-dropdown-item><el-dropdown-item v-if="!isMyself(msgBody)" @click="informOnMessage(msgBody)">举报</el-dropdown-item></el-dropdown-menu></template></el-dropdown></div><div v-if="msgBody.isRecall" class="recall_style">{{ isMyself(msgBody) ? "你" : `${msgBody.from}`}}撤回了一条消息<span class="reEdit" v-show="isMyself(msgBody) && msgBody.type === ALL_MESSAGE_TYPE.TEXT"@click="reEdit(msgBody.msg)">重新编辑</span></div><div v-if="msgBody.type === ALL_MESSAGE_TYPE.INFORM" class="inform_style"><p>{{ msgBody.msg }}</p></div></div><ReportMessage ref="reportMessage" /></div></template>
</script>

了解即时通讯IM及应用场景请访问:环信官网
更多集成IM教程请访问:IMGeek社区


http://www.ppmy.cn/news/653098.html

相关文章

开源即时通讯IM框架 MobileIMSDK v6.3 发布

一、更新内容简介 本次更新为次要版本更新&#xff0c;进行了若干优化&#xff08;更新历史详见&#xff1a;码云 Release Nodes&#xff09;。可能是市面上唯一同时支持UDPTCPWebSocket 三种协议的同类开源IM框架。 二、MobileIMSDK简介 MobileIMSDK是一套专为移动端开发的原创…

victoriametrics 时序数据库概述

目录标题 victoriametrics 时序数据库的组成victoriametrics 常用的查询指令 victoriametrics 时序数据库的组成 VictoriaMetrics 存储数据的数据结构主要由以下几个方面组成&#xff1a; Metric 标识符&#xff08;Metric Identifier&#xff09;&#xff1a;Metric 标识符是…

吃饭咯 干锅肥肠 + 掌中宝!

干饭人 吃了4碗米饭&#x1f35a; 哈哈哈哈

《烹煮人生》------六种常见料汁的黄金配比

六种常见料汁的黄金配比 要想菜做的好吃&#xff0c;各种酱汁的制作那是必不可少的&#xff0c;很多人菜做的不好吃都是调料的配比不到位&#xff0c;下面整理了六种常见的料汁配比&#xff0c;需要的可以参考一下。 一. 鱼香汁 比例是4&#xff1a;3&#xff1a;2&#xff1a;…

为何现在好多饭店熬汤不用骨头也能熬出来浓白色的汤?

我在烹饪学校学过三年的厨师&#xff0c;毕业以后又在大大小小的饭店工作过&#xff0c;后来自己又开了接近10年的饭店&#xff0c;对于饭店后厨的那些事&#xff0c;还是比较了解的。 中国菜在没有味素和其它增鲜调料发明以前&#xff0c;基本都是靠调配高汤来给菜肴增鲜提味…

国庆假期吃肥仔烧排骨

刚刚浏览点评的时候看到火炉山&#xff0c;自然想起肥仔。每次到火炉山&#xff0c;基本都吃烧排骨。有时是特意来吃。前天就去了&#xff0c;下午6点半左右到。 我历来是知道这里生意火的&#xff0c;今天可是未曾见过的火。座无虚席&#xff0c;人声鼎沸。此外服务台还围了一…

双立人锅,你是一口锅还是一个爹?

有几天听一个同事说想买一种进口的锅&#xff0c;说是那锅特好用特耐用&#xff0c;一口锅可以用几代人&#xff0c;品牌好象叫双立人什么的。今天偶尔在电视购物频道看到在卖双立人锅&#xff0c;于是特意去网上查了一下&#xff0c;看看那锅到底是什么神物&#xff0c;跟前两…

灭菌锅原理、结构和检测方法浅析

1、背景 公司项目设计到灭菌锅&#xff0c;因此有必要对灭菌锅的原理、结构和检测方法做一定的了解。本文从网络中查阅资料后整理。若有不正确的地方&#xff0c;欢迎指正。 1.1.参考资料 http://www.doc88.com/p-2252808115533.html https://www.xianjichina.com/news/det…