一、相关参考资料
1、网易API文档
dev.yunxin.163.com/docs/interf…
2、网易IM开发手册
dev.yunxin.163.com/docs/produc…
3、参考博文
4、netease-nim-web-sdk依赖
注:官网的H5端Demo二次开发比较麻烦,整合到已有项目中很浪费时间,所以
二、使用方法
1、获取自己的appKey,具体步骤网易云信官网有,很简单
2、安装netease-nim-web-sdk依赖
npm i netease-nim-web-sdk -S
3、在main.js中引入依赖,并绑定到Vue原型链上,作为全局使用的变量
引入:import NIM from 'netease-nim-web-sdk';
绑定Vue原型链:Vue.prototype.$NIM = NIM;
4、在mixins目录下新建一个Nim.js文件,全局配置连接IM会话
重要参数说明:
appKey: '3689d88258e2c8ffb49a8bc1141ece8a', // 自己申请的appKey
account: this.account.imId, // 从后台接口获取通信对象的imId
token: this.account.imToken, // 从后台接口中获取通信对象的token
/**
* IM实时通信
*/
export default {
data() {
return {
myNim: {},
msg: {}
};
},
methods: {
initNIM() {
// 注意这里, 引入的 SDK 文件不一样的话, 你可能需要使用 SDK.NIM.getInstance 来调用接口
this.myNim = this.$NIM.getInstance({
debug: false,
appKey: '3689d88258e2c8ffb49a8bc1141ece8a', // 自己申请的appKey
account: this.account.imId,
token: this.account.imToken,
db: true, // 若不要开启数据库请设置false。SDK默认为true。
// privateConf: {}, // 私有化部署方案所需的配置
onconnect: this.onConnect,
onwillreconnect: this.onWillReconnect,
ondisconnect: this.onDisconnect,
onerror: this.onError
});
this.$store.commit('setNIM', this.myNim);
console.log(this.myNim);
},
onConnect(success) {
console.log('连接成功');
},
onWillReconnect(obj) {
// 此时说明 SDK 已经断开连接, 请开发者在界面上提示用户连接已断开, 而且正在重新建立连接
console.log('即将重连');
},
onDisconnect(error) {
// 此时说明 SDK 处于断开状态, 开发者此时应该根据错误码提示相应的错误信息, 并且跳转到登录页面
console.log('丢失连接');
if (error) {
switch (error.code) {
// 账号或者密码错误, 请跳转到登录页面并提示错误
case 302:
break;
// 重复登录, 已经在其它端登录了, 请跳转到登录页面并提示错误
case 417:
break;
// 被踢, 请提示错误后跳转到登录页面
case 'kicked':
break;
default:
break;
}
}
},
onError(error) {
console.log(error);
}
}
};
5、在main.js中引入Nim.js,并混入mixin
引入:import MyNim from '@/mixins/Nim';
注入mixins:Vue.mixin(MyNIM);
6、页面中使用(主要包括发送图片、文本消息,目前暂不支持语音、表情发送,后期会拓展)
<template>
<div class="chat-wrapper">
<new-layout>
<template slot="top">
<new-header :centerTitle="$route.query.user"></new-header>
</template>
<template slot="center">
<div ref="main_content" class="main-content">
<sessionList
v-if="historySession.length !== 0"
:list="historySession"
></sessionList>
</div>
</template>
<template slot="bottom">
<div class="action">
<div class="action-main__area">
<!--<icon-btn :iconName="audioIcon" @click.native="madeAudio"/>-->
<!--输入区域-->
<div class="input-wrap">
<input
ref="input"
type="text"
v-model="inputValue"
@click="onFocus"
>
<!--<div-->
<!--ref="touch-audio"-->
<!--v-if="showAudioBtn"-->
<!--class="audioBtn disabled-select"-->
<!-->-->
<!--按住说话-->
<!--</div>-->
</div>
<!--<icon-btn :iconName="expressionIcon" size=".74rem"/>-->
<icon-btn v-if="!showSendBtn" iconName="tianjia" size=".8rem" @click.native="showActions"/>
<div
v-if="showSendBtn"
class="send flex-base"
:class="showSendBtn ? 'transformBtn' : ''"
@click="sendContent"
>
发送
</div>
</div>
<div class="action-sub__area"
:style="{borderTop: showActionArea ? borderTopStyle : ''}"
>
<div class="face-container"></div>
<div
v-if="showActionArea"
class="action-container flex-base"
>
<div class="item flex-base">
<div class="btn flex-base">
<i class="van-icon van-icon-tupian"></i>
</div>
<label>相册</label>
<input @change="changeFiles($event)" id="upload-files" type="file" accept='image/gif, image/jpeg, image/jpg, image/png, image/svg'/>
</div>
</div>
</div>
</div>
</template>
</new-layout>
</div>
</template>
<style scoped lang="scss">
$containerHeight: 100px;
$padding: 20px;
.main-content{
padding: $padding;
}
.action{
&-main__area{
padding: $padding;
margin: 10px auto;
height: $containerHeight;
display: flex;
align-items: center;
justify-content: space-between;
.input-wrap{
flex: 1;
height: 80px;
margin-right: 20px;
border-radius: 50px;
input{
width: 100%;
height: 100%;
padding: 15px;
border-radius: 50px;
background: #F5F5F5;
border: 1px solid #d4d4d4;
}
.audioBtn{
width: 100%;
height: 100%;
border-radius: 10px;
background: #F5F5F5;
display: flex;
align-items: center;
justify-content: center;
}
}
.send{
height: 60px;
padding: 0 20px;
color: #FFF;
font-size: 25px;
background: $chatMainColor;
border-radius: 15px;
}
}
&-sub__area{
.action-container{
padding: 30px;
justify-content: space-between;
.item{
position: relative;
flex-flow: column;
#upload-files{
opacity: 0;
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
}
.btn{
width: 100px;
height: 100px;
margin-bottom: 15px;
border-radius: 10px;
background: $chatMainColor;
color: #FFF;
font-size: 65px;
justify-content: center;
}
label{
font-size: 28px;
}
}
}
}
}
</style>
<script>
import sessionList from '@/components/chats/sessionList';
export default {
name: 'ChatView',
components: {
sessionList
},
data () {
return {
toClient: this.$route.query.chatId,
inputValue: '',
inputRef: '',
audioIcon: 'saying',
expressionIcon: 'smiling',
showAudioBtn: false,
showActionArea: false,
borderTopStyle: '1px solid #F5F5F5',
nim: {},
showSendBtn: false,
historySession: [],
sendMsg: '',
sendFiles: {},
willBeSendImg: {}
}
},
watch: {
inputValue (value) {
if (value) {
this.showSendBtn = true;
} else {
this.showSendBtn = false;
}
}
},
methods: {
initSession () {
this.$NIM.getInstance({
debug: false,
appKey: '3689d88258e2c8ffb49a8bc1141ece8a',
account: this.account.imId,
token: this.account.imToken,
db: true,
onmsg: this.watchOnMsg, // 监听消息
// 同步完成
onsyncdone: this.onSyncDone // 同步消息
});
},
// 获取消息
watchOnMsg(msg) {
this.pushMsg(msg);
},
/**
* 发送文本消息
*/
sendMessages () {
this.sendMsg = this.nim.sendText({
scene: 'p2p',
to: this.toClient,
text: this.inputValue,
done: this.sendMsgDone
});
},
sendMsgDone () {
console.log('-----sendMsgDone____发送信息方法:----');
console.log(this.sendMsg);
this.inputValue = '';
this.pushMsg(this.sendMsg);
},
// 上传图片
changeFiles (e) {
console.log('文件对象:');
console.log(e.target.files);
let size = e.target.files[0].size;
if (size > 3145728) {
this.$toast('图片大小不能大于3M');
} else {
this.sendFilesMsg();
}
},
// 发送图片
sendFilesMsg () {
this.nim.sendFile({
scene: 'p2p',
to: this.toClient,
type: 'image',
fileInput: 'upload-files',
uploadprogress: obj => {
this.$toast.loading('发送中...');
},
uploaddone: (error, file) => {
this.$toast.loading('发送成功!');
this.$toast.clear();
},
beforesend: msg => {
this.pushMsg(msg);
this.showActionArea = false;
}
});
},
onSyncDone () {
this.getHistoryMsg();
},
// 获取历史会话信息
getHistoryMsg () {
this.nim.getHistoryMsgs({
scene: 'p2p',
to: this.toClient,
done: this.getHistoryMsgsDone
});
},
getHistoryMsgsDone(error, obj) {
if (!error) {
this.historySession = obj.msgs.reverse();
}
this.scrollToBottom();
},
pushMsg(msg) {
this.historySession.push(msg);
this.scrollToBottom();
},
// 发送内容
sendContent () {
this.sendMessages();
},
// input无延时聚集
onFocus () {
this.inputRef.focus();
},
// madeAudio () {
// if (this.audioIcon === 'saying') {
// this.audioIcon = 'jianpan';
// this.showAudioBtn = true;
// } else {
// this.audioIcon = 'saying';
// this.showAudioBtn = false;
// }
// },
showActions () {
this.showActionArea = !this.showActionArea;
this.scrollToBottom();
},
scrollToBottom () {
this.$nextTick(() => {
setTimeout(() => {
// let mainCon = document.getElementById('main_content');
let mainCon = this.$refs.main_content;
let mainConHeight = mainCon.clientHeight;
// console.log('mainConHeight: ');
// console.log(mainConHeight);
let centerWrapper = document.getElementById('center_wrapper');
// console.log('centerWrapper_clientHeight: ');
// console.log(centerWrapper.clientHeight);
centerWrapper.scrollTop = mainConHeight - centerWrapper.clientHeight;
// console.log('scrollTop: ');
// console.log(centerWrapper.scrollTop);
}, 500);
});
}
},
created () {
},
mounted () {
let _this = this;
this.nim = this.$store.state.myNim;
this.initSession();
this.getHistoryMsg(); // 获取历史会话
this.$nextTick(() => {
_this.inputRef = this.$refs.input;
});
}
};
</script>