vue-cli接入融云实现即时通讯

介绍

由于有同窗问了我下融云怎么写聊天的问题,我才了解到有融云这么个东西,尝试着学了下。主要介绍了vue中使用vue-cli接入融云实现即时通讯的相关资料,本文经过实例代码给你们介绍的很是详细,具备必定的参考借鉴价值,须要的朋友能够参考下... 我的博客javascript

本文章 Demo 源码 star 哦 拿下来能够直接跑css

Flutter 项目 star 哦 这是本人打算长期更新的一个项目html

准备

注册融云拿到 APPKEY 和 TOKEN

在写代码以前咱们首先要 注册融云,注册融云后拿到 appkey 和融云提供的 tokenvue

拿到 appkey 和 token 后记得保存下来java

安装 Vue CLI

能够使用下列任一命令安装这个新的包:git

$ npm install -g @vue/cli
# OR
$ yarn global add @vue/cli
复制代码

建立一个项目

运行如下命令来建立一个新项目:github

$ vue create hello-world
# OR
$ vue ui  // UI 界面建立项目
复制代码

你会被提示选取一个 prese 由于咱们这个项目用到了 VUEX 因此咱们选择手动选择特性来选取须要的特性来避免后续的的麻烦web

除了默认选项 咱们须要选择 RouterVuexvuex

等项目建立完毕后大概是这个样子vue-cli

开始编写咱们的代码

在这之间仍是但愿你们去过一遍官方文档后来看个人文章

Web SDK 开发指南

引入融云 Web SDK

首先咱们进入根目录的 public 目录下的 index.html 这个位置引入融云 SDK

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>im</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but im doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>

    <script src="https://cdn.ronghub.com/RongIMLib-2.5.0.min.js"></script>
    <!-- built files will be auto injected -->
  </body>
</html>
复制代码

咱们先在根目录 src 下建立几个文件 名字随意你们能够自行建立

  • 建立一个js文件 utils.js
  • 建立 scss 目录 在此目录建立一个 utils.scss (这个文件并不重要只是为了自适应)
  • scr 目录下建立 init.vue
  • src 目录下建立 RongCloud.vue
  • src 目录下建立 Message.vue

开始撸代码

utils.js 此文件是对融云的初始化操做

export const init = (params, addPromptInfo) => {
  var appkey = params.appkey
  var token = params.token
  RongIMClient.init(appkey)
  RongIMClient.setConnectionStatusListener({
    onChanged: function (status) {
      switch (status) {
        case RongIMLib.ConnectionStatus['CONNECTED']:
        case 0:
          addPromptInfo('链接成功')
          break

        case RongIMLib.ConnectionStatus['CONNECTING']:
        case 1:
          addPromptInfo('正在链接中')
          break

        case RongIMLib.ConnectionStatus['DISCONNECTED']:
        case 2:
          addPromptInfo('当前用户主动断开连接')
          break

        case RongIMLib.ConnectionStatus['NETWORK_UNAVAILABLE']:
        case 3:
          addPromptInfo('网络不可用')
          break

        case RongIMLib.ConnectionStatus['CONNECTION_CLOSED']:
        case 4:
          addPromptInfo('未知缘由,链接关闭')
          break

        case RongIMLib.ConnectionStatus['KICKED_OFFLINE_BY_OTHER_CLIENT']:
        case 6:
          addPromptInfo('用户帐户在其余设备登陆,本机会被踢掉线')
          break

        case RongIMLib.ConnectionStatus['DOMAIN_INCORRECT']:
        case 12:
          addPromptInfo('当前运行域名错误,请检查安全域名配置')
          break
      }
    }
  })

  // 消息监听器
  RongIMClient.setOnReceiveMessageListener({
    // 接收到的消息
    onReceived: function (message) {
      // 判断消息类型
      switch (message.messageType) {
        case RongIMClient.MessageType.TextMessage:
          // message.content.content => 文字内容
          addPromptInfo('新消息 ' + message.targetId + ':' + JSON.stringify(message))
          break
        case RongIMClient.MessageType.VoiceMessage:
          // message.content.content => 格式为 AMR 的音频 base64
          break
        case RongIMClient.MessageType.ImageMessage:
          // message.content.content => 图片缩略图 base64
          // message.content.imageUri => 原图 URL
          break
        case RongIMClient.MessageType.LocationMessage:
          // message.content.latiude => 纬度
          // message.content.longitude => 经度
          // message.content.content => 位置图片 base64
          break
        case RongIMClient.MessageType.RichContentMessage:
          // message.content.content => 文本消息内容
          // message.content.imageUri => 图片 base64
          // message.content.url => 原图 URL
          break
        case RongIMClient.MessageType.InformationNotificationMessage:
          // do something
          break
        case RongIMClient.MessageType.ContactNotificationMessage:
          // do something
          break
        case RongIMClient.MessageType.ProfileNotificationMessage:
          // do something
          break
        case RongIMClient.MessageType.CommandNotificationMessage:
          // do something
          break
        case RongIMClient.MessageType.CommandMessage:
          // do something
          break
        case RongIMClient.MessageType.UnknownMessage:
          // do something
          break
        default:
        // do something
      }
    }
  })

  RongIMClient.connect(token, {
    onSuccess: function (userId) {
      addPromptInfo('链接成功,用户id:' + userId, userId)
    },
    onTokenIncorrect: function () {
      addPromptInfo('token无效')
    },
    onError: function (errorCode) {
      switch (errorCode) {
        case RongIMLib.ErrorCode.TIMEOUT:
          addPromptInfo('超时')
          //连接超时进行从新的连接start
          var callback = {
            onSuccess: function (userId) {
              console.log("Reconnect successfully." + userId);
            },
            onTokenIncorrect: function () {
              console.log('token无效');
            },
            onError: function (errorCode) {
              console.log(errorcode);
            }
          };
          var config = {
            // 默认 false, true 启用自动重连,启用则为必选参数
            auto: true,
            // 重试频率 [100, 1000, 3000, 6000, 10000, 18000] 单位为毫秒,可选
            url: 'cdn.ronghub.com/RongIMLib-2.5.0.min.js',
            rate: [100, 1000, 3000, 6000, 10000]
          };
          RongIMClient.reconnect(callback, config);
          //连接超时进行从新连接end
          break;
        case RongIMLib.ErrorCode.UNKNOWN_ERROR:
          addPromptInfo('未知错误')
          break;
        case RongIMLib.ErrorCode.UNACCEPTABLE_PaROTOCOL_VERSION:
          addPromptInfo('不可接受的协议版本')
          break;
        case RongIMLib.ErrorCode.IDENTIFIER_REJECTED:
          console.log('ddd')
          addPromptInfo('appkey不正确')
          break;
        case RongIMLib.ErrorCode.SERVER_UNAVAILABLE:
          addPromptInfo('服务器不可用')
          break;
      }
      addPromptInfo(errorCode)
    }
  }, null)
}
复制代码

utils.scss 这个文件很简单

@function vw ($px) {
  @return $px / 750px * 100vw;
}
复制代码

init.vue 经过用户输入的信息来进行初始化链接

<template>
  <div class="init">
    <van-nav-bar title="链接融云" />
    <van-cell-group>
      <van-field v-model="appkey" required label="appkey" placeholder="请输入您的 appkey" />
      <van-field v-model="token" label="token" placeholder="请输入您的 token" required />
      <van-field v-model="targetId" label="targetId" placeholder="请输入 targetId" required />
    </van-cell-group>
    <van-button class="init-button" type="info" @click="initRongCloud">初始化链接</van-button>
    <div class="rong-show-box">
      <p v-for="data in showDatas" v-bind:key="data">
        {{data}}
      </p>
    </div>
  </div>
</template>

<script> import { init } from '@/utils.js' export default { data () { return { appkey: '', // 这是咱们以前保存的 appkey *重要 token: '', // token 能够屡次生成 以前也有介绍过 targetId: '', // 你要给谁发送消息 目标ID showDatas: [], // 初始化信息 } }, methods: { addPromptInfo (prompt, userId = null) { const _this = this const avatarList = [ 'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=4100987808,2324741924&fm=26&gp=0.jpg', 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2988245209,2476612762&fm=26&gp=0.jpg', 'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=4259300811,497831842&fm=26&gp=0.jpg', 'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3684587473,1286660191&fm=26&gp=0.jpg', 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2884107401,3797902000&fm=26&gp=0.jpg' ] // 真实环境是经过登陆 后台接口返回的 token 拿到的用户信息 我在这为为了模拟 因此给初始化后的用户随机生成一个头像 const avatar = avatarList[Math.floor(Math.random() * (3 + 1))] _this.showDatas.push(prompt) const timer = setInterval(() => { if (userId) { clearInterval(timer) // 路由跳转后销毁定时器 _this.$store.commit('SET_MEMBER', { // 保存用户信息 userId: userId, avatar: avatar }) _this.$store.commit('SET_TARGETID', _this.targetId) // 保存目标ID _this.$router.push({ name: 'RongCloud' }) } }, 500) }, initRongCloud () { var appkey = this.appkey var token = this.token if (!appkey || !token) { alert('appkey 和 token 不能为空') } else { // 这个init 是咱们以前撸的 `utils.js` init({ appkey: appkey, token: token }, this.addPromptInfo) } } } } </script>

<style lang="scss" scoped> @import "~@/scss/utils"; .init-button { position: fixed !important; bottom: vw(30px); left: 50%; transform: translateX(-50%); } .rong-show-box { margin-top: vw(100px); text-align: center; } </style>
复制代码

RongCloud.vue 发送消息

<template>
  <div id='rongcloud'>
    <van-nav-bar title="融云聊天" fixed left-text="返回" left-arrow @click-left="onClickLeft" />
    <div class="wrapper">
      <Message v-for="(item, index) in answer" :key="index" :data='item' />
    </div>
    <div class="send-message">
      <van-field v-model="say" class="message-textarea" type="textarea" placeholder="请输入..." />
      <van-button class="send-button" type="info" size="small" @click="sendMessage">发送</van-button>
    </div>
  </div>
</template>

<script> import { mapState } from 'vuex' import Message from './Message' export default { components: { Message }, data () { return { say: '' // 消息 } }, created () { this.$nextTick(() => { const list = document.getElementById('rongcloud') document.documentElement.scrollTop = list.scrollHeight //如不行,请尝试-> list.scrollTop = list.scrollHeight }) }, watch: { answer () { this.$nextTick(() => { const list = document.getElementById('rongcloud') document.documentElement.scrollTop = list.scrollHeight //如不行,请尝试-> list.scrollTop = list.scrollHeight }) } }, computed: { ...mapState({ answer: 'answer', // 消息列表 memberInfo: 'memberInfo', // 用户信息 targetId: 'targetId' // 目标ID }) }, methods: { onClickLeft () { this.$router.go(-1) }, sendMessage () { const _this = this var msg = new RongIMLib.TextMessage({ content: _this.say, extra: _this.memberInfo.avatar }); var conversationType = RongIMLib.ConversationType.PRIVATE // 单聊, 其余会话选择相应的消息类型便可 var targetId = this.targetId // 目标 Id RongIMClient.getInstance().sendMessage(conversationType, targetId, msg, { onSuccess: function (message) { // message 为发送的消息对象而且包含服务器返回的消息惟一 Id 和发送消息时间戳 const say = { css: 'right', txt: message.content.content, headImg: _this.memberInfo.avatar } _this.answer.push(say) _this.say = '' }, onError: function (errorCode, message) { var info = '' switch (errorCode) { case RongIMLib.ErrorCode.TIMEOUT: info = '超时' break case RongIMLib.ErrorCode.UNKNOWN: info = '未知错误' break case RongIMLib.ErrorCode.REJECTED_BY_BLACKLIST: info = '在黑名单中,没法向对方发送消息' break case RongIMLib.ErrorCode.NOT_IN_DISCUSSION: info = '不在讨论组中' break case RongIMLib.ErrorCode.NOT_IN_GROUP: info = '不在群组中' break case RongIMLib.ErrorCode.NOT_IN_CHATROOM: info = '不在聊天室中' break } console.log('发送失败: ' + info + errorCode) } }) } } } </script>

<style lang="scss" scoped> @import "~@/scss/utils"; .wrapper { padding-top: vw(92px); padding-bottom: vw(200px); } .send-message { width: 100vw; height: vw(200px); position: fixed !important; bottom: 0; left: 0; .message-textarea { height: 100%; } .send-button { position: fixed; right: vw(30px); bottom: vw(30px); } } </style>
复制代码

Message.vue 显示消息 逻辑比较简单就不讲了

<template>
  <div>
    <div v-if="data.css === 'left'">
      <div class="message left">
        <van-image round fit="cover" width="2rem" height="2rem" :src="data.headImg" />
        <span>{{data.txt}}</span>
      </div>
    </div>
    <div v-if="data.css === 'right'">
      <div class="message right">
        <span>{{data.txt}}</span>
        <van-image round fit="cover" width="2rem" height="2rem" :src="data.headImg" />
      </div>
    </div>
  </div>
</template>

<script> export default { props: ['data'] } </script>

<style lang="scss" scoped> @import "~@/scss/utils"; .message { display: flex; align-items: center; padding: vw(10px); } .left { justify-content: flex-start; span { margin-left: vw(20px); } } .right { justify-content: flex-end; span { margin-right: vw(20px); } } </style>
复制代码

store.js 此demo的一些状态管理数据

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
  memberInfo: undefined,  // 用户信息
  targetId: undefined,    // 目标ID
  answer: []              // 消息列表
}
const mutations = {
  SET_MEMBER (state, memberInfo) {
    state.memberInfo = memberInfo
  },
  SET_TARGETID (state, targetId) {
    state.targetId = targetId
  },
  SET_ANSWER (state, playload) {
    let say = {
      css: 'left',            // css 样式
      txt: playload.content,  // 文本内容
      headImg: playload.extra // 头像
    }
    state.answer.push(say)
  },
};

export default new Vuex.Store({
  state,
  mutations,
  actions
})
复制代码

最后一步咱们须要在 utils.js 文件中引入store 保存发送的消息到 answer

import store from './store'

export const init = (params, addPromptInfo) => {
 ...
  // 消息监听器
  RongIMClient.setOnReceiveMessageListener({
    // 接收到的消息
    onReceived: function (message) {
      // 判断消息类型
      switch (message.messageType) {
        case RongIMClient.MessageType.TextMessage:
          // message.content.content => 文字内容
          store.commit('SET_ANSWER', message.content)
        ...
      }
    }
  })
  ...
}
复制代码

结尾

我的博客 本 demo 是给你们实现一个基本思路,只是实现了一个一对一聊天的功能。如需更多功能,请自行深刻了解,谢谢

本文章 Demo 源码
Flutter 项目

相关文章
相关标签/搜索