关于项目集成腾讯IM即时通讯相关记录

2020/4/2 11:02:24

本文主要是介绍关于项目集成腾讯IM即时通讯相关记录,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

本文是基于web平台对接腾讯IM的一些体会和总结,对于没有对接IM经验或者是刚接触IM项目的小伙伴来说,看到这么多可选的平台,这么丰富的接口和看似如此庞大的项目,你的心里可能会发怵,但是,当你看到这篇文章的时候,你应该不会慌了,因为这里整理了web端跑通整个demo对接的基本流程很一些问题,话不多说,继续往下看。

腾讯IM提供在线demo和本地demo,在线demo可以查看官方案例的最完整的功能,本地demo是供本地开发调试时使用,以web平台为例,去SDK下载区下载对应平台的demo,如果是Web(通)平台找到这个H5/dist/debug/GenerateTestUserSig.js目录,把文件中的SDKAPPIDSECRETKEY项换成自己的,在项目目录下安装依赖npm install,启动本地项目npm start注意,官方不推荐直接访问http://localhost:8080,而是在项目的dist目录下直接打开index.html,这时候我们可以在user0-user29中随便登陆一个了,重新打开一次,再登录一个账户,两个账户就可以即时通讯,至此,官方demo在本地跑起来了。那么,我们如何集成SDK到我们自己的web项目呢?

目前,很多前端web项目都采用MV*框架,比如官方的demo就采用Vue+ElementUI技术,因此,先安装SDK依赖

// IM Web SDK
npm install tim-js-sdk --save
// 发送图片、文件等消息需要的 COS SDK
npm install cos-js-sdk-v5 --save
复制代码

为了实现模块化,我们新建tim.js文件作为tim模块独立出来,引入对应的包,并导出tim

import TIM from 'tim-js-sdk';
import COS from "cos-js-sdk-v5";

let options = {
  SDKAppID: 0 // 接入时需要将0替换为您的即时通信 IM 应用的 SDKAppID
};
// 创建 SDK 实例,`TIM.create()`方法对于同一个 `SDKAppID` 只会返回同一份实例
let tim = TIM.create(options); // SDK 实例通常用 tim 表示

// 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明
tim.setLogLevel(0); // 普通级别,日志量较多,接入时建议使用
// tim.setLogLevel(1); // release 级别,SDK 输出关键信息,生产环境时建议使用

// 注册 COS SDK 插件
tim.registerPlugin({'cos-js-sdk': COS});

export default tim
复制代码

为了能在本地登录账户,需要利用客户端计算UserSig生成签名,再配上userID,就可以登录到IM系统,这里需要借助官方demo的两个文件GenerateTestUserSig.jslib-generate-test-usersig.min.js来生成签名,由于模块化开发,需要对GenerateTestUserSig.js进行修改

//首先导入lib-generate-test-usersig.min.js
import  LibGenerateTestUserSig from './lib-generate-test-usersig.min'
//......
//修改lib的调用方法,官方案例是注入在window里面new window.LibGenerateTestUserSig(...)
var generator = new LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME);
//......
//导出
export {
  genTestUserSig
}
复制代码

为了方便后续使用,我们可以在window和Vue中全局注入tim

//main.js
import tim from './tim'
import TIM from 'tim-js-sdk'

window.tim = tim
window.TIM = TIM
Vue.prototype.tim = tim
Vue.prototype.TIM = TIM
复制代码

接下来需要添加事件监听,查看所有的事件绑定,执行登录操作,顺便提下退出操作

//登录
tim.login({userID: 'your userID', userSig: 'your userSig'}).then((imRespone)=>{
  console.log(imResponse.data); // 登录成功
}).catch((imError)=>{
  console.warn('login error:', imError); // 登录失败的相关信息
})
//退出
tim.logout().then((imResponse)=>{
  console.log(imResponse.data); // 退出成功
}).catch((imError)=>{
  console.warn('logout error:', imError);
});
复制代码

登录之后我们可以获取会话列表,获取每个会话下面的消息列表,其中涉及到的数据状态和细节操作是比较复杂的,先看看文本中的表情处理,这里简要说下思路。

//emojiMap.js
export const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/'
export const emojiMap = {
  '[调皮]': 'emoji_113@2x.png',
  '[龇牙]': 'emoji_141@2x.png'
}
export const emojiName = [
  '[龇牙]',
  '[调皮]'
]
复制代码

据官方demo来看,所有的表情都是图片的映射,比如[微笑](https://imgcache.qq.com/open/qcloud/tim/assets/emoji/emoji_49@2x.png,只需要更改结尾,拼凑图片链接即可,显示 供选择的时候就通过img标签遍历显示,发送消息的时候,我们选择了某个表情,只需要把对于的emojiName比如'[微笑]'追加到文本消息里就行。接下来是接收带有表情的文本消息解析的问题,官方给出了解析代码,只需要导入emoji映射,再把这个解析函数导出就可以了。

然后就是发送文件信息,获取对应的文件DOM,调用发送文件消息的接口即可,显示的时候只需要显示文件名和文件大小即可,然后点击下载,可参考下面三个函数

size() {
  const size = this.payload.fileSize
    if (size > 1024) {
      if (size / 1024 > 1024) {
        return `${this.toFixed(size / 1024 / 1024)} Mb`
      }
      return `${this.toFixed(size / 1024)} Kb`
    }
    return `${this.toFixed(size)}B`
},
toFixed(number, precision = 2) {
  return number.toFixed(precision)
}
downloadFile() {
  // 浏览器支持fetch则用blob下载,避免浏览器点击a标签,跳转到新页面预览的行为
  if (window.fetch) {
    fetch(this.fileUrl)
      .then(res => res.blob())
      .then(blob => {
        let a = document.createElement('a')
        let url = window.URL.createObjectURL(blob)
        a.href = url
        a.download = this.fileName
        a.click()
      })
  } else {
    let a = document.createElement('a')
    a.href = this.fileUrl
    a.target = '_blank'
    a.download = this.filename
    a.click()
  }
}
复制代码

图片消息和文件消息大同小异,需要注意的是这里图片消息是可以点击放大缩小旋转查看的,下面贴上官方demo中写的图片操作,经供参考,icon是Iview的

<template>
  <div class="image-previewer-wrapper" v-show="showPreviewer" @mousewheel="handleMouseWheel">
    <div class="image-wrapper">
      <img
        class="image-preview"
        :style="{transform: `scale(${zoom}) rotate(${rotate}deg)`}"
        :src="previewUrl"
        @click="close"
      />
    </div>
    <Icon type="md-close" class="close-button"  @click="close" />
    <Icon type="md-arrow-back" class="prev-button"  @click="goPrev" />
    <Icon type="md-arrow-forward" class="next-button" @click="goNext"></Icon>
    <div class="actions-bar">
      <Icon type="ios-remove-circle-outline" @click="zoomOut"></Icon>
      <Icon type="ios-add-circle-outline" @click="zoomIn"></Icon>
      <Icon type="md-undo" @click="rotateLeft"></Icon>
      <Icon type="md-redo" @click="rotateRight"></Icon>
      <span class="image-counter">{{index+1}} / {{imgUrlList.length}}</span>
    </div>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
export default {
  name: 'ImagePreviewer',
  data() {
    return {
      url: '',
      index: 0,
      visible: false,
      zoom: 1,
      rotate: 0,
      minZoom: 0.1
    }
  },
  computed: {
    ...mapGetters(['imgUrlList']),
    showPreviewer() {
      return this.url.length > 0 && this.visible
    },
    imageStyle() {
      return {
        transform: `scale(${this.zoom});`
      }
    },
    previewUrl() {
      return this.formatUrl(this.imgUrlList[this.index])
    }
  },
  mounted() {
    this.$bus.$on('image-preview', this.handlePreview)
  },
  methods: {
    handlePreview({ url }) {
      this.url = url
      this.index = this.imgUrlList.findIndex(item => item === url)
      this.visible = true
    },
    handleMouseWheel(event) {
      if (event.wheelDelta > 0) {
        this.zoomIn()
      } else {
        this.zoomOut()
      }
    },
    zoomIn() {
      this.zoom += 0.1
    },
    zoomOut() {
      this.zoom =
        this.zoom - 0.1 > this.minZoom ? this.zoom - 0.1 : this.minZoom
    },
    close() {
      Object.assign(this, { zoom: 1 })
      this.visible = false
    },
    rotateLeft() {
      this.rotate -= 90
    },
    rotateRight() {
      this.rotate += 90
    },
    goNext() {
      this.index = (this.index + 1) % this.imgUrlList.length
    },
    goPrev() {
      this.index =
        this.index - 1 >= 0 ? this.index - 1 : this.imgUrlList.length - 1
    },
    formatUrl(url) {
      if (!url) {
        return ''
      }
      return url.slice(0, 2) === '//' ? `https:${url}` : url
    }
  }
}
</script>

<style scoped>
.image-previewer-wrapper {
  position: fixed;
  width: 100%;
  left: 0;
  top: 0;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  background: rgba(14, 12, 12, 0.7);
  z-index: 2000;
  cursor: zoom-out;
}

.close-button {
  cursor: pointer;
  font-size: 28px;
  color: #000;
  position: fixed;
  top: 50px;
  right: 50px;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 50%;
  padding: 6px;
}
.image-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.image-preview {
  transition: transform 0.1s ease 0s;
}
.actions-bar {
  display: flex;
  justify-content: space-around;
  align-items: center;
  position: fixed;
  bottom: 50px;
  left: 50%;
  margin-left: -100px;
  padding: 12px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.8);
}
.actions-bar i {
  font-size: 24px;
  cursor: pointer;
  margin: 0 6px;
}

.prev-button,
.next-button {
  position: fixed;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 50%;
  font-size: 24px;
  padding: 12px;
}
.prev-button {
  left: 0;
  top: 50%;
}
.next-button {
  right: 0;
  top: 50%;
}
.image-counter {
  background: rgba(20, 18, 20, 0.53);
  padding: 3px;
  border-radius: 3px;
  color: #fff;
}
</style>
复制代码


这篇关于关于项目集成腾讯IM即时通讯相关记录的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程