vue 接入网易云信IM实时通讯【H5移动端】

3,465 阅读3分钟

一、相关参考资料

1、网易API文档

dev.yunxin.163.com/docs/interf…

2、网易IM开发手册

dev.yunxin.163.com/docs/produc…

3、参考博文

www.jianshu.com/p/2a601fe11…

4、netease-nim-web-sdk依赖

www.npmjs.com/package/net…

注:官网的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"-->
                  <!--&gt;-->
                    <!--按住说话-->
                  <!--</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>