环信聊天室使用文档(详细版)
最近项目在做直播聊天室,第三方使用的通讯工具是环信,项目已经上线,在这里把用到的所有方法做个笔记。
功能:实现文本聊天,表情包,图片发送,语音功能
先附上环信的说明文档:https://docs-im.easemob.com/im/web/intro/start,说明文档和实际实现还是有点距离,期间我踩了不少坑,也打了不少补丁,下面我会把遇到的问题都标注出来的。环信的listen监听的主要是非当前登录用户的事件,当前登录用户需调用文档中的其他方法。
引入环信的SDK
需要注意:WebIMConfig文件是一些配置项,主要把appkey换成自己的,私有云配置请设置 isHttpDNS,https这个选项如果需要支持语音的话,这个值必须是true,浏览器调起本地音频设备,协议必须要https接下来在WebIM.js中注册
初始化IM SDK
// An highlighted block
// 监听各种通讯状态
import config from "./WebIMConfig";
import websdk from "easemob-websdk";
import _ from 'lodash'
import { Message } from "element-ui";
import store from "@/store/index";
var WebIM = {};
WebIM = window.WebIM = websdk;
WebIM.config = config;
WebIM.conn = new WebIM.connection({
appKey: WebIM.config.appkey,
isHttpDNS: WebIM.config.isHttpDNS,
isMultiLoginSessions: WebIM.config.isMultiLoginSessions,
https: WebIM.config.https,
url: WebIM.config.socketServer,
apiUrl: WebIM.config.restServer,
isAutoLogin: WebIM.config.isAutoLogin,
autoReconnectNumMax: WebIM.config.autoReconnectNumMax,
autoReconnectInterval: WebIM.config.autoReconnectInterval,
delivery: WebIM.config.delivery,
useOwnUploadFun: WebIM.config.useOwnUploadFun,
deviceId: 'window_client'
});
// 注册监听回调
WebIM.conn.listen({
onOpened: function () { // 连接成功回调
console.log(’连接成功')
//登录聊天室状态变更,调接口获取token,登录环信WebIM.conn.open(this.options);
store.commit('global/changeLoginStatue',true)
},
onClosed: function (message) {
console.log('链接关闭'+message)
}, // 连接关闭回调
onTextMessage: function (message) {
message.ext.isSelf = false
store.commit('global/pushChatMessage',message)
},// 收到文本消息
onEmojiMessage: function (message) {
message.ext.isSelf = false
store.commit('global/pushChatMessage',message)
}, // 收到表情消息
onPictureMessage: function (message) {
message.msgType = 'img'
let index = message.url.indexOf('&',0)
if(index !== -1){
message.url = message.url.replace("&","?")
}
store.commit('global/pushChatMessage',message)
}, // 收到图片消息
onCmdMessage: function (message) {
store.commit('global/setcmdMessage',message)
},
onAudioMessage: function (message) {
message.ext.isSelf = false
let index = message.url.indexOf('&',0)
if(index !== -1){
message.url = message.url.replace("&","?")
}
message.audioSrcUrl = message.url
message.msgType = 'audio'
let options = {
url: message.audioSrcUrl,
headers: {
Accept: 'audio/mp3'
},
onFileDownloadComplete: function (response) {
let objectUrl = WebIM.utils.parseDownloadResponse.call(WebIM.conn, response)
message.audioSrcUrl = objectUrl //url
store.commit('global/pushChatMessage',message)
},
onFileDownloadError: function () {
console.log('音频发送失败')
}
}
WebIM.utils.download.call(WebIM.conn, options)
}, // 收到音频消息
onRecallMessage: message => {
store.commit('global/mergeMemberChatMessage',message)
},
onReceivedMessage: function (message) {
console.log("回执消息", message)
store.commit('global/mergeReturnChatMessage',message)
}, // 收到消息送达服务器回执
onMutedMessage: function() {
Message.warning('您已被禁言')
},// 如果用户在A群组被禁言,在A群发消息会走这个回调并且消息不会传递给群其它成员
onOnline: function () {
console.log("onOnline 网络已连接");
}, // 本机网络连接成功
onOffline: function () {
store.commit('global/retryErrFlg',true)
console.log("onOffline 网络已断开");
store.commit('global/retryErrFlg',true)
}, // 本机网络掉线
onError: function (message) {
if (message.type == 0) {
return Message.warning('请输入账号密码')
} else if (message.type == 28) {
return console.log("未登陆")
} else if (_.get(message,'data.type') === 17 && JSON.parse(message.data.data).error_description == "user not found") {
return Message.warning("用户名不存在!")
} else if (_.get(message,'data.type') === 17 && JSON.parse(message.data.data).error_description == "invalid password") {
return Message.warning('密码无效!')
} else if (_.get(message,'data.type') === 17 && JSON.parse(message.data.data).error_description == "user not activated") {
return Message.warning("用户已被封禁!")
} else if (message.type == "504") {
return Message.warning("消息撤回失败");
}
}, // 失败回调
// 创建群组成功回执(需调用createGroupNew)
onPresence: function (msg) {
//监听管理员添加/移出及用户加入聊天室等
switch(msg.type){
case 'muteChatRoom':
// 聊天室一键禁言
break;
case 'addMute':
// 禁言
// Message.warning('您已被禁言')
break;
case 'removeAdmin':
// 移除管理员
store.commit('global/removeChatAdmin',msg.to)
break;
case 'addAdmin': //添加管理员
store.commit('global/addChatAdmin',msg.to)
break;
case 'memberJoinChatRoomSuccess':
// 加入聊天室
store.commit('global/pushMemberList',msg)
break;
default:
break;
}
}
});
export default WebIM;
WebIMl监听实现好了。
页面操作开始
1.登录环信
joinChat() {
let options = {
roomId: this.chatRoomId, // 聊天室id
};
WebIM.conn.joinChatRoom(options).then((res) => {
if (res) {
this.getChatRoomAdminHandle(); //获取聊天室管理员
// this.sendDanmu('欢迎'+res.data.user+'加入聊天室', true)
}
});
},
获取聊天室管理员
getChatRoomAdminHandle() {
let options = {
chatRoomId: this.chatRoomId,
};
WebIM.conn.getChatRoomAdmin(options).then((res) => {
res.data.map((item) => {
store.commit("global/addChatAdmin", item)
});
});
},
3.获取历史记录
loadMoreMsgs() {
let that = this
if (this.chatList.length === 0) {
this.loadText = "已无更多数据";
}
var options = {
queue: this.chatRoomId,
isGroup: true,
count: 200,
// start:id
success: function (result) {
console.log("获取拉取成功的历史消息",result);
result.map((item )=>{
if(item.contentsType !== 'COMMAND'){//过滤command信息
if(item.contentsType === 'TEXT'){
let self = item.ext.isSelf || false
that.sendDanmu(item.data, self)
}
store.commit("global/pushChatMessage", item);
}
})
},
fail: function (result) {
console.log("get history error" + result);
},
};
WebIM.conn.fetchHistoryMessages(options);
},
4.聊天室发送文本消息
sendChat() {
const that = this;
if (this.inputVal === "" || this.inputVal == "\n") {
this.$message("聊天内容不能空");
return false;
}
if (this.inputVal.length > 20) {
this.$message("聊天内容不能超过20字符");
}
let chatValue = this.inputVal;
this.inputVal = "";
this.chatVisible = false;
const id = WebIM.conn.getUniqueId(); // 生成本地消息id
const msgObj = new WebIM.message("txt", id); // 创建文本消息
let option = {
msg: chatValue, // 消息内容
to: this.chatRoomId, // 接收消息对象(聊天室id)
chatType: "chatRoom", // 聊天室
ext: this.ext, // 扩展消息
success: function () {
store.commit("global/pushChatMessage", msgObj.body);
// 当前用户发送消息,列表自动滚动到最底层
store.commit("global/changeStopScroll", false);
}, // 对成功的相关定义,sdk会将消息id登记到日志进行备份处理
fail: function (err) {
that.$message(err.reason || err.message);
}, // 对失败的相关定义,sdk会将消息id登记到日志进行备份处理
};
msgObj.set(option);
WebIM.conn.send(msgObj.body);
}
5.发送图片
showImageHandle() {
let img = this.$refs.imgDom;
img && img.click();
},
pictureChange() {
let img = this.$refs.imgDom;
let file = WebIM.utils.getFileUrl(img); // 将图片转化为二进制文件
if (!file.filename) {
this.$refs.imgDom.value = null
return false
}
// 判断图片大小
let imgFileSize =file.data.size/(1024*1000)
if(imgFileSize>10){
this.$refs.imgDom.value = null;
// this.$emit('changeVisableEvent')
this.$message.error("图片大小不能超过10M")
return false
}
// if (!Config.imgType[file.filetype.toLowerCase()]) {
// this.$refs.imgDom.value = null;
// this.$message.error("不支持此类型文件");
// return;
// }
let obj = {
chatType: this.type,
chatId: this.chatId, //TODO 这里在群里面应该取的是ID,后期跟进
file: file,
roomType: "chatroom",
};
this.chatImageInfoHandle(obj)
},
chatImageInfoHandle(imageObj) {
let that = this;
let file = imageObj.file;
var id = WebIM.conn.getUniqueId(); // 生成本地消息id
var msgObj = new WebIM.message("img", id); // 创建图片消息
this.ext["file_length"] = file.data.size;
var allowType = {
jpg: true,
jpeg: true,
gif: true,
png: true,
bmp: true,
};
if (file.filetype.toLowerCase() in allowType) {
var option = {
file: file,
ext: this.ext, // 扩展消息
to: this.chatRoomId, // 接收消息对象
chatType: "chatRoom", // 聊天类型
onFileUploadError: function (e) {
// 消息上传失败
console.log("onFileUploadError", e);
},
onFileUploadComplete: function (res) {
// 消息上传成功
msgObj.body.url = `${res.uri}/${res.entities[0].uuid}`;
},
success: function () {
// 消息发送成功
msgObj.body.msgType = "img";
store.commit("global/pushChatMessage", msgObj.body);
},
fail: function (err) {
that.$message.warning(err.message); //如禁言、拉黑后发送消息会失败
},
flashUpload: WebIM.flashUpload,
};
msgObj.set(option);
WebIM.conn.send(msgObj.body);
}
},
6.发送语音
sendVideoMessage(audioObj) {
const that = this;
const id = WebIM.conn.getUniqueId();
const msgObj = new WebIM.message("audio", id);
let audioSrcUrl = ""; //保存上传成功语音url
let voiceLength = "";
msgObj.set({
file: audioObj,
to: that.chatRoomId,
length: audioObj.length,
type: "audio",
chatType: "chatroom",
ext: this.ext, // 扩展消息
onFileUploadError: function (error) {
that.$message("语音上传失败", error);
},
onFileUploadComplete: function (data) {
voiceLength = data.length;
audioSrcUrl = data.uri + "/" + data.entities[0].uuid;
},
success: function (data) {
console.log("语音发送成功", data);
msgObj.body.audioSrcUrl = audioSrcUrl;
msgObj.body.file_length = voiceLength;
msgObj.body.length = voiceLength;
msgObj.body.ext = that.ext;
msgObj.body.msgType = "audio";
store.commit("global/pushChatMessage", msgObj.body);
},
fail: function (err) {
that.$message.warning(err.message); //如禁言、拉黑后发送消息会失败
},
flashUpload: WebIM.flashUpload,
});
WebIM.conn.send(msgObj.body);
},
7.撤回信息
recallMessageHandle: function (item) {
const that = this;
try {
const option = {
mid: item.id,
to: that.chatRoomId,
type: "chatroom",
success: function (result) {
if (result) {
store.commit("global/recallChatMessage", item);
}
document.body.click();
},
fail: function (err) {
that.$message.warning(err.reason || err.message);
},
};
WebIM.conn.recallMessage(option);
} catch (err) {
console.log(err);
}
store.commit("global/changeStopScroll", false);
},
8.禁言
silenceHandle(scope) {
let options = {
chatRoomId: this.chatRoomId, // 聊天室id
username: scope.ext.mtime_im_id, // 被禁言的聊天室成员的id
muteDuration: -1000, // 被禁言的时长,单位ms,如果是“-1000”代表永久
};
WebIM.conn.muteChatRoomMember(options).then((res) => {
if (res.status === 401) {
this.$message({
type: "warning",
message: "登录过期,请重新登录!",
});
} else if (res.status === 404) {
this.$message({
type: "warning",
message: " 聊天室不存在!",
});
} else {
this.$message({
type: "success",
message: "禁言成功",
});
document.body.click();
}
});
store.commit("global/changeStopScroll", false);
},
9.离开聊天室
destroyed() {
//登出
WebIM.conn.close();
},
其他问题
关于管理员权限:这个必须要自己去区分,我选择在ext中加权限标识,然后采用不同模板渲染,避免用值去判断方法。
关于emoji
使用emoj Icom,弹幕也支持,直接走发送文本的方法,也不用单独判断咯。省时省力
emoji_icon: [
“😀”,
“😃”,
“😄”,
“😁”,
“😆”,
“😅”,
“🤣”,
“😂”,
“🙂”,
“🙃”,
“😉”,
“😊”,
“😇”,
“😍”,
“🤩”,
“😘”,
“😗”,
“😚”,
“😙”,
“😋”,
“😛”,
“😜”,
“🤪”,
“😝”,
“🤑”,
“🤗”,
“🤭”,
“🤫”,
“🤔”,
“🤐”,
“🤨”,
“😐”,
“😑”,
“😶”,
“😏”,
“😒”,
“🙄”,
“😬”,
“🤥”,
“😌”,
“😔”,
“😪”,
“🤤”,
“😴”,
“😷”,
“🤒”,
“🤕”,
“🤢”,
“🤮”,
“🤧”,
“😵”,
“🤯”,
“🤠”,
“😎”,
“🤓”,
“🧐”,
“😕”,
“😟”,
“🙁”,
“😮”,
“😯”,
“😲”,
“😳”,
“😦”,
“😧”,
“😨”,
“😰”,
“😥”,
“😢”,
“😭”,
“😱”,
“😖”,
“😣”,
“😞”,
“😓”,
“😩”,
“😫”,
“😤”,
“😡”,
“😠”,
“🤬”,
“😈”,
“👿”,
“💀”,
“💩”,
“🤡”,
“👹”,
“👺”,
“👻”,
“👽”,
“👾”,
“🤖”,
“😺”,
“😸”,
“😹”,
“😻”,
“😼”,
“😽”,
“🙀”,
“😿”,
“😾”,
“💋”,
“👋”,
“🤚”,
“🖐”,
“✋”,
“🖖”,
“👌”,
“🤞”,
“🤟”,
“🤘”,
“🤙”,
“👈”,
“👉”,
“👆”,
“🖕”,
“👇”,
“👍”,
“👎”,
“✊”,
“👊”,
“🤛”,
“🤜”,
“👏”,
“🙌”,
“👐”,
“🤲”,
“🤝”,
“🙏”,
“💅”,
“🤳”,
“💪”,
“👂”,
“👃”,
“🧠”,
“👀”,
“👁”,
“👅”,
“👄”,
“👶”,
“🧒”,
“👦”,
“👧”,
“🧑”,
“👱”,
“👨”,
“🧔”,
“👱”,
“👨”,
“👨”,
“👨”,
“👨”,
“👩”,
“👱”,
“👩”,
“👩”,
“👩”,
“👩”,
“🧓”,
“👴”,
“👵”,
“🙍”,
“🙍”,
“🙍”,
“🙎”,
“🙎”,
“🙎”,
“🙅”,
“🙅”,
“🙅”,
“🙆”,
“🙆”,
“🙆”,
“💁”,
“💁”,
“💁”,
“🙋”,
“🙋”,
“🙋”,
“🙇”,
“🙇”,
“🙇”,
“🤦”,
“🤦”,
“🤦”,
“🤷”,
“🤷”,
“🤷”,
“👨⚕️”,
“👩⚕️”,
“👨🎓”,
“👩🎓”,
“👨🏫”,
“👩🏫”,
“👨⚖️”,
“👩⚖️”,
“👨🌾”,
“👩🌾”,
“👨🍳”,
“👩🍳”,
“👨🔧”,
“👩🔧”,
“👨🏭”,
“👩🏭”,
“👨💼”,
“👩💼”,
“👨🔬”,
“👩🔬”,
“👨💻”,
“👩💻”,
“👨🎤”,
“👩🎤”,
“👨🎨”,
“👩🎨”,
“👨✈️”,
“👩✈️”,
“👨🚀”,
“👩🚀”,
“👨🚒”,
“👩🚒”,
“👮”,
“👮♂️”,
“👮♀️”,
“🕵”,
“🕵️♂️”,
“🕵️♀️”,
“💂”,
“💂”,
“💂”,
“👷”,
“👷”,
“👷”,
“🤴”,
“👸”,
“👳”,
“👳”,
“👳”,
“👲”,
“🧕”,
“🤵”,
“👰”,
“🤰”,
“🤱”,
“👼”,
“🎅”,
“🤶”,
“🧙”,
“🧙”,
“🧙”,
“🧚”,
“🧚”,
“🧚”,
“🧛”,
“🧛”,
“🧛”,
“🧜”,
“🧜”,
“🧜”,
“🧝”,
“🧝”,
“🧝”,
“🧞”,
“🧞”,
“🧞”,
“🧟”,
“🧟”,
“🧟”,
“💆”,
“💆”,
“💆”,
“💇”,
“💇”,
“💇”,
“🚶”,
“🚶”,
“🚶”,
“🏃”,
“🏃”,
“🏃”,
“💃”,
“🕺”,
“🕴”,
“👯”,
“👯”,
“👯”,
“🧖”,
“🧖”,
“🧖”,
“🧘”,
“👭”,
“👫”,
“👬”,
“💏”,
“👨”,
“👩”,
“💑”,
“👨”,
“👩”,
“👪”,
“👨👩👦”,
“👨👩👧”,
“👨👩👧👦”,
“👨👩👦👦”,
“👨👩👧👧”,
“👨👨👦”,
“👨👨👧”,
“👨👨👧👦”,
“👨👨👦👦”,
“👨👨👧👧”,
“👩👩👦”,
“👩👩👧”,
“👩👩👧👦”,
“👩👩👦👦”,
“👩👩👧👧”,
“👨👦”,
“👨👦👦”,
“👨👧”,
“👨👧👦”,
“👨👧👧”,
“👩👦”,
“👩👦👦”,
“👩👧”,
“👩👧👦”,
“👩👧👧”,
“🗣”,
“👤”,
“👥”,
“👣”,
“🌂”,
“☂”,
“👓”,
“🕶”,
“👔”,
“👕”,
“👖”,
“🧣”,
“🧤”,
“🧥”,
“🧦”,
“👗”,
“👘”,
“👙”,
“👚”,
“👛”,
“👜”,
“👝”,
“🎒”,
“👞”,
“👟”,
“👠”,
“👡”,
“👢”,
“👑”,
“👒”,
“🎩”,
“🎓”,
“🧢”,
“⛑”,
“💄”,
“💍”,
“💼”
]