IM 即时通讯实战:环信Web IM极速集成,实现发送消息
Posted 环信即时通讯云
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IM 即时通讯实战:环信Web IM极速集成,实现发送消息相关的知识,希望对你有一定的参考价值。
前置技能
- Node.js 环境已搭建。
- npm 包管理工具的基本使用。
- Vue2 或者 Vue3 框架基本掌握或使用。
学习目标
- 项目中集成 IM 即时通讯实战
- 利用环信 IM Web SDK 快速实现在 Vue.js 中发送出一条 Hello World!
一、了解环信 IM
-
什么是环信 IM?
环信即时通讯为开发者提供高可靠、低时延、高并发、安全、全球化的通信云服务,支持单聊、群聊、聊天室。提供多平台 SDK 支持,包括:android、ios、Web;同时,提供 EaseIM 和 EaseIMKit 以及服务端 REST API,帮助开发者快速构建端到端通信的场景。
-
学习完环信 WebIM 之后可以干嘛?
可以在任意 Web 应用中极速集成搭建即时通讯功能,无论是自己搭建 IM 应用,还是实现产品需求均可以灵活集成进入到自己的项目之中。
二、环信 WebIM 实现通讯的基本流程
前置准备
- 有效的开发者 AppKey。 ( 注册环信)(注册参考文档)
- 使用 Vue-cli 创建一个空白项目,或已经具备已有待集成项目(此篇文章以 Vue3 为示例,Vue2 同样可以参考此文章)。
- 在项目中使用 npm 或者 yarn 安装环信 WebSDK 包,easemob-websdk。
- 下载环信官方 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: '', //你的测试环信ID
password: '' //你的测试环信ID密码
)
//登录接口调用
const loginIM = async () =>
try
await EaseChatClient.open(
user: loginValue.username.toLowerCase(),
pwd: loginValue.password.toLowerCase()
);
catch (error)
console.log('>>>>登录失败', error);
</script>
紧接着是开始聊天部分。
好友关系
完成这个功能 需要将该项目开启两个页面,一个申请,一个接收,这样才能看到效果
两种方式:手动关联一个好友,第二种再创建一个测试 ID 之后,调用 SDK 添加好友。
方式一:测试时最简单的方式,手动关联好友
- 在管理后台中手动再创建一个 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*$/)) return
const msgOptions =
id: nowPickInfo.value.id, //要发送的目标ID
chatType: 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, //消息来源ID
id:"1111864344594875684", //消息的唯一ID
msg:"Hello World!",//消息内容
time:1676440891009,//消息发送时间
to:myId,//发送目标ID
type:"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 * 10px`">
<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" /集成环信IM入门教程——如何导入及运iOS demo