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 項目

相關文章
相關標籤/搜索