欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Vue Cli 3项目使用融云IM实现聊天功能的方法

程序员文章站 2023-12-16 11:53:52
介绍:前台使用vue开发的单页面,后台使用ant design pro单页面,实现手机端和后台聊天功能。 效果如图(pc+移动): 一、申请融云账号(tok...

介绍:前台使用vue开发的单页面,后台使用ant design pro单页面,实现手机端和后台聊天功能。

效果如图(pc+移动):

Vue Cli 3项目使用融云IM实现聊天功能的方法

Vue Cli 3项目使用融云IM实现聊天功能的方法

一、申请融云账号(token、appkey)

建议先看教程:sdk使用介绍

过一遍教程,接下来开始写

二、引入融云im

如图:

Vue Cli 3项目使用融云IM实现聊天功能的方法

位置:public/index.html,引入

<script src="https://cdn.ronghub.com/rongimlib-2.3.5.min.js"></script>

三、可以正常使用rongimlib其自带方法了

app.vue 不是全代码(因为只是连接)

created () { //生命周期函数-可发起求
 let that = this
 //融云初始化
 rongimlib.rongimclient.init('4z3hrv4ovrt'); //------------------------------重要填写appkey
 that.beforeim() //设置监听,必须先设置监听,再连接
 that.nowim() //连接融云
 },
 methods: {
 ...mapmutations({ //读取最新消息列表,并设置----------------------------重要
  getanswer:'getanswer'
 }),
 beforeim(){
  let that = this
  // 连接状态监听器
  rongimclient.setconnectionstatuslistener({
   onchanged: function (status) {
    // status 标识当前连接状态
    switch (status) {
     case rongimlib.connectionstatus.connected:
      console.log('链接成功');
      break;
     case rongimlib.connectionstatus.connecting:
      console.log('正在链接');
      break;
     case rongimlib.connectionstatus.disconnected:
      console.log('断开连接');
      break;
     case rongimlib.connectionstatus.kicked_offline_by_other_client:
      console.log('其他设备登录');
      break;
     case rongimlib.connectionstatus.domain_incorrect:
      console.log('域名不正确');
      break;
     case rongimlib.connectionstatus.network_unavailable:
      console.log('网络不可用');
      break;
    }
   }
  });

  // 消息监听器
  rongimclient.setonreceivemessagelistener({
   // 接收到的消息
   onreceived: function (message) {
    // 判断消息类型
    switch(message.messagetype){
     case rongimclient.messagetype.textmessage:
      // message.content.content => 文字内容
      //----------------------------重要-------把获取的消息存放在store中,全局公用homeim.vue要使用
      console.log('8080',message,message.content.content)
      that.getanswer(message.content)
      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
    }
   }
  });
 },
 nowim(){
 //自己的token------从接口获取,写到缓存
  var token = json.parse(localstorage.getitem('userinfo')).imuser.token//"wzrthc5f4ufuii7diwcq5fwtgfqcdobpowizkcqnj8pqoquajb/nii1ayzgfwjguvbqzxbjh3x0=";
  rongimclient.connect(token, {
   onsuccess: function(userid) {
    console.log('connect successfully. ' + userid);
   },
   ontokenincorrect: function() {
    console.log('token 无效');
   },
   onerror: function(errorcode){
    var info = '';
    switch (errorcode) {
     case rongimlib.errorcode.timeout:
      info = '超时';
      break;
     case rongimlib.connectionstate.unacceptable_parotocol_version:
      info = '不可接受的协议版本';
      break;
     case rongimlib.connectionstate.identifier_rejected:
      info = 'appkey不正确';
      break;
     case rongimlib.connectionstate.server_unavailable:
      info = '服务器不可用';
      break;
    }
    console.log(info);
   }
  });
 }
 },

main.js 代码

import vue from 'vue'
import app from './app.vue'
import router from './router'
import store from './store'
import './assets/style.css' // 外部static样式 ------重要
import './assets/js/rem.js' //rem适配 ------重要
import my from './assets/js/lbc.js' //------不重要 ---自定义全局方法

import homenews from './components/homenews.vue' //自定义组件 ------重要
vue.component('homenews',homenews)

vue.prototype.$my=my //------不重要 ---自定义全局方法 使用 this.$my.xxx
vue.config.productiontip = false

new vue({
 router,
 store,
 render: h => h(app)
}).$mount('#app')

store.js 全代码

import vue from 'vue'
import vuex from 'vuex'
import axios from 'axios'
const api_proxy = 'https://bird.ioliu.cn/v1/?url='; //代理

vue.use(vuex)
export default new vuex.store({
 state: {
 answer:[]
 },
 getters: {
 },
 mutations: {
 getanswer (state, playload) {//--------------重要
  let say ={ //自定义消息组件所需参数
   type:1,
   css:'left',
   txt:playload.content,
   date:'',
   headimg:playload.extra
  }
  state.answer.push(say)
  console.log(playload)
 },
 },
 actions: {
 }
})

homeim.vue

//一如以往,不废话,直接代码
<template>
 <div class="homeim" id='homeim'>
 //----------------------------------------------------重要-------------------自定义消息组件,下面会贴码
 <home-news v-for="(item ,index) in answer" :key='index' :item='item' :data='item'></home-news>

 <div class="posfix bottom0 left0 flex justsa alic w100 bgf " style="min-height:.6rem;">
  <img src="../assets/images/mike.png" class="mike pl10 pr10"/>
  <van-field v-model="say" placeholder="请输入" class="flex1 border borrad" />
  <van-button size="large " @click="send" type='info' class="button borrad ml10 mr10" :disabled ='say?false:true'>确定</van-button>
 </div>
 
 </div>
</template>

<script>
import vue from "vue";
import { field ,button } from "vant";
import router from "../router.js";
import axios from "axios";
import {mapstate,mapgetters,mapactions,mapmutations} from 'vuex'


const arr = [ field ,button];
arr.map(e => {
 //动态生成组件
 vue.use(e);
});

export default {
 data() {
 return { 
  say:'小仙女,你好鸭'
 };
 },
 name: "homeim",
 props: {
 msg: string
 },
 created() {
 //this.getchatrecord() //获取聊天记录,要钱
 this.$nexttick(() => {//------------------------重要-------有消息就滚动到底部-----------------------
  let list = document.getelementbyid('homeim')
  document.documentelement.scrolltop = list.scrollheight
  //如不行,请尝试-> list.scrolltop = list.scrollheight
  })
 },
 computed:{
 ...mapstate({
  answer:"answer",
 }),

 },
 watch: { //------------------------重要-------有消息就滚动到底部-----------------------
 answer() {
  this.$nexttick(() => {
  let list = document.getelementbyid('homeim')
  document.documentelement.scrolltop = list.scrollheight
  //如不行,请尝试-> list.scrolltop = list.scrollheight
  })
 }
 },
 methods: {
 send() {
  let that = this
  let msg = new rongimlib.textmessage({ content: that.say, extra: 'https://img.52z.com/upload/news/image/20171120/20171120080335_21404.jpg' });
  let conversationtype = rongimlib.conversationtype.private; // 单聊, 其他会话选择相应的消息类型即可
  let targetid = json.parse(localstorage.getitem('userinfo')).imuser.assistantid; // 目标 id

  rongimclient.getinstance().sendmessage(conversationtype, targetid, msg, {
   onsuccess: function (message) {
    // message 为发送的消息对象并且包含服务器返回的消息唯一 id 和发送消息时间戳
    console.log('send successfully',message,message.content.content);
    let say = {
     type:1,
     css:'right',
     txt:message.content.content,
     headimg:'https://img.52z.com/upload/news/image/20171120/20171120080335_21404.jpg'
    }
    that.answer.push(say)
    that.say = ''
   },
   onerror: function (errorcode, message) {
    let 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);
   }
  });
 },
 getchatrecord(){
  let conversationtype = rongimlib.conversationtype.private; //单聊, 其他会话选择相应的消息类型即可
  let targetid = '2'; // 想获取自己和谁的历史消息,targetid 赋值为对方的 id
  let timestrap = null; // 默认传 null,若从头开始获取历史消息,请赋值为 0, timestrap = 0;
  let count = 20; // 每次获取的历史消息条数,范围 0-20 条,可以多次获取
  rongimlib.rongimclient.getinstance().gethistorymessages(conversationtype, targetid, timestrap, count, {
   onsuccess: function(list, hasmsg) {
    // list => message 数组。
    // hasmsg => 是否还有历史消息可以获取。
    console.log('历史纪录',list, hasmsg)
   },
   onerror: function(error) {
    console.log('gethistorymessages, errorcode:' + error);
   }
  });
 }
 },
};
</script>

<!-- add "scoped" attribute to limit css to this component only -->
<style scoped>
.mike{
 width: .3rem;height: .3rem;
}
.border{border:1px solid #ccc;}
.button{
 width: .8rem;height: .46rem;
}
.homeim{padding-bottom: .7rem;}
</style>

homenews.vue 全代码

<template>
 <div class="homenews">
  <!-- 1:文字,2:红包,3:文章 ,css:类型 -->
  <div v-if="data.type == 1&&data.css == 'left'">
   <div class="colora1 fz12 lh40 pt10">{{data.date}}</div>
   <div class="flex pl20 pr20 borbox">
   <img :src="data.headimg" class="head borrad">
   <div class="frame borrad bgf lh24 fz16 tl color3 pl10 pr10 pt10 pb10 borbox w250 ml15 posrel">
    {{data.txt}}
   </div>
   </div>
  </div>
  <router-link to="/homeredbag" v-else-if="data.type == 2&&data.css == 'left'">
   <div class="colora1 fz12 lh40 pt10">{{data.date}}</div>
   <div class="flex pl20 pr20 borbox">
   <img :src="data.headimg" class="head borrad">
   <div class="frame borrad bgf9 lh24 fz16 tl colorf w200 ml15 posrel redframe">
    <div class="flex alic pl10 pr10 pt10 pb10 borbox">
    <img src="../assets/images/redtabs.png" class="redtabs"/>
    <span class="pl10">{{data.title}}</span>
    </div>
    <div class="fz12 color6 bgf pl15 borbox txt">{{data.txt}}</div>
   </div>
   </div>
  </router-link>
  <router-link to="/homearticle" v-else-if="data.type == 3&&data.css == 'left'">
   <div class="colora1 fz12 lh40 pt10">{{data.date}}</div>
   <div class="flex pl20 pr20 borbox">
   <img :src="data.headimg" class="head borrad">
   <div class="frame borrad bgf fz16 tl color3 pl10 pr10 pt10 pb10 borbox w250 ml15 posrel">
    <div class="fz20 txt2 mb10 lh30">{{data.title}}</div>
    <div class="flex justsa alic">
    <div class="colora1 txt2 flex1 lh20">{{data.txt}}</div>
    <img :src="data.banner" class="banner"/>
    </div>
   </div>
   </div>
  </router-link>
  <div v-if="data.type == 1&&data.css == 'right'">
  <div class="colora1 fz12 lh40 pt10">{{data.date}}</div>
  <div class="flex pl20 pr20 borbox juste">
   <div class="frame-right borrad bgf lh24 fz16 tl color3 pl10 pr10 pt10 pb10 borbox w250 mr15 posrel">
   {{data.txt}}
   </div>
   <img :src="data.headimg" class="head borrad">
  </div>
  </div>

 </div>
</template>
<script>
import vue from "vue";
import router from "../router.js";
export default {
 name: "homenews",
 props:['data'],
 data() {
 return {
 };
 },
 created() {
 console.log()
 },
 methods: {
 }
};
</script>
<!-- add "scoped" attribute to limit css to this component only -->
<style scoped>
.head {
 width: 0.36rem;
 height: 0.36rem;
}
.frame::before {
 display: block;
 content: '';
 width: 0px; /* 宽高设置为0,很重要,否则达不到效果 */
 height: 0px;
 border: .10rem solid #fff;
 border-bottom-color: transparent; /* 设置透明背景色 */
 border-top-color: transparent;
 border-left-color: transparent;
 position: absolute;left:-.2rem;top:.1rem;
}
.frame-right::before{
 display: block;
 content: '';
 width: 0px; /* 宽高设置为0,很重要,否则达不到效果 */
 height: 0px;
 border: .10rem solid #fff;
 border-bottom-color: transparent; /* 设置透明背景色 */
 border-top-color: transparent;
 border-right-color: transparent;
 position: absolute;right:-.2rem;top:.1rem;
}
.redframe::before{
 display: block;
 content: '';
 width: 0px; /* 宽高设置为0,很重要,否则达不到效果 */
 height: 0px;
 border: .10rem solid #f99f3e;
 border-bottom-color: transparent; /* 设置透明背景色 */
 border-top-color: transparent;
 border-left-color: transparent;
 position: absolute;left:-.2rem;top:.1rem;
}
.redframe-right::before{
 display: block;
 content: '';
 width: 0px; /* 宽高设置为0,很重要,否则达不到效果 */
 height: 0px;
 border: .10rem solid #f99f3e;
 border-bottom-color: transparent; /* 设置透明背景色 */
 border-top-color: transparent;
 border-left-color: transparent;
 position: absolute;right:-.2rem;top:.1rem;
}
.w250{max-width: 2.5rem;}
.w200{max-width: 2rem;}
.redtabs{
 width: .32rem;
 height:.39rem;
}
.txt{
 border-bottom-left-radius: .05rem;
 border-bottom-right-radius: .05rem;
}
.banner{width: .4rem;height: .4rem;}
</style>
style.css 我自己的样式表
@charset "utf-8";
/* css document 刘白超修改于2019/3/10*/
html,body{height: 100%;width: 100%;word-wrap:break-word;}
*{margin: 0;padding: 0;}
.tc{text-align: center}
.tr{text-align: right}
.tl{text-align: left}
.vm{vertical-align: middle;}
.vs{vertical-align: sub;}
.fl{float: left;}
.fr{float: right;}
.fz24{font-size: .24rem;}
.fz20{font-size: .2rem;}
.fz18{font-size: .18rem;}
.fz16{font-size: .16rem;}
.fz14{font-size: .14rem;}
.fz12{font-size: .12rem;}
.fw{font-weight: 600;}
.mr5{margin-right: .05rem}
.mr10{margin-right: .10rem}
.mr15{margin-right: .15rem}
.mr20{margin-right: .20rem}
.ml5{margin-left:.05rem;}
.ml10{margin-left:.10rem;}
.ml15{margin-left:.15rem;}
.ml20{margin-left:.20rem;}
.ml24{margin-left:.24rem;}
.mt40{margin-top:.40rem;}
.mt20{margin-top: .20rem;}
.mt15{margin-top: .15rem;}
.mt10{margin-top: .10rem;}
.mt5{margin-top: .05rem;}
.mb5{margin-bottom: .05rem;}
.mb10{margin-bottom: .10rem;}
.mb15{margin-bottom: .15rem;}
.mb20{margin-bottom: .20rem;}
.pt5{padding-top: .05rem;}
.pt10{padding-top: .10rem;}
.pt15{padding-top: .15rem;}
.pt20{padding-top: .20rem;}
.pt30{padding-top: .30rem;}
.pb5{padding-bottom: .05rem;}
.pb10{padding-bottom: .10rem;}
.pb15{padding-bottom: .15rem;}
.pb20{padding-bottom: .20rem;}
.pl5{padding-left: .05rem;}
.pl10{padding-left: .10rem;}
.pl15{padding-left: .15rem;}
.pl20{padding-left: .20rem;}
.pl30{padding-left: .30rem;}
.pr5{padding-right: .05rem;}
.pr10{padding-right: .10rem;}
.pr15{padding-right: .15rem;}
.pr20{padding-right: .20rem;}
.pr30{padding-right: .30rem;}
.bgef{background: #efefef;}
.bgf{background: #fff;}
.bgf9{background: #f99f3e}
.ee {background: #eee;}
.bg259{background:#259dff !important}
.colordd{color: #dd4d41}
.colorf9 {color: #ff9800;}
.colore5{color: #e51c23;}
.colorf{color: #fff;}
.color3{color: #333;}
.color6{color: #666;}
.color9{color: #999;}
.colora1{color:#a1a1a1}
.color259{color:#259dff}
.color005{color:#00559b}
.colorf3{color:#f3665e}
.lh24{line-height: .24rem}
.lh20{line-height: .20rem;}
.lh30{line-height: .30rem;}
.lh40{line-height: .40rem;}
.lh50{line-height: .50rem;}
.lh60{line-height: .60rem;}
.hide{display: none}
.show{display: block}
.inline{display: inline-block;}
.indent2{text-indent: 2em;}
.txt2{
 overflow : hidden;
 text-overflow: ellipsis;
 display: -webkit-box;
 -webkit-line-clamp: 2;
 -webkit-box-orient: vertical;
}
.wn{white-space:nowrap;}
.flex{display: flex;}
.flex1{flex:1;}
.colu{flex-direction: column;}
.justc{justify-content: center;}
.justs{justify-content: space-between}/*两端对齐*/
.justsa{justify-content: space-around}/*分散对齐*/
.juste{justify-content: flex-end;}
.alic{align-items: center}
.wrap{flex-wrap:wrap}
.childend{align-self:flex-end;}
.posabs{position: absolute;}
.posrel{position: relative;}
.posfix{position: fixed;}
.top0{top:0;}
.bottom0{bottom:0;}
.left0{left:0;}
.right0{right: 0;}
.w100{width: 100%}
.h100{height: 100%}
.borbox{box-sizing: border-box;}
.borderte0{border-top:1px solid #e0e0e0; }
.borderbe0{border-bottom:1px solid #e0e0e0; }
.borrad{border-radius:.05rem;}
.over{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}
.overh{overflow: hidden}
.clear{zoom:1;}
.clear:after{content: "\0020";display: block;height: 0;clear: both;}
.mask{width: 100%;height: 100%;background: rgba(20, 20, 20, 0.5);position: fixed;z-index: 5;top: 0;left: 0;}
.cursor{cursor: pointer;}
.noclick{pointer-events: none;}
li{list-style:none;}
a{text-decoration:none;color:#555;}
a:hover{color:#555;}
img{display:block;vertical-align:middle;}
a img,fieldset{border:0;}
i,em{font-style:normal}
b,strong,th{font-weight:100;}
input,textarea,select{outline:none;}
textarea{resize:none;}
table{border-collapse:collapse;}
.btn{
 width: calc(100% - .54rem);
 background: #259dff;
 font: .2rem/.5rem "";
 text-align: center;
 color: #fff;
 border-radius: 5px;
 margin-left: .27rem;
}
rem.js rem自适应单位
//例如设计稿为375,最大宽度为750,则为(375,750)
!function(e,t){function n(){var n=l.getboundingclientrect().width;t=t||540,n>t&&(n=t);var i=100*n/e;r.innerhtml="html{font-size:"+i+"px;}"}var i,d=document,o=window,l=d.documentelement,r=document.createelement("style");if(l.firstelementchild)l.firstelementchild.appendchild(r);else{var a=d.createelement("div");a.appendchild(r),d.write(a.innerhtml),a=null}n(),o.addeventlistener("resize",function(){cleartimeout(i),i=settimeout(n,300)},!1),o.addeventlistener("pageshow",function(e){e.persisted&&(cleartimeout(i),i=settimeout(n,300))},!1),"complete"===d.readystate?d.body.style.fontsize="16px":d.addeventlistener("domcontentloaded",function(e){d.body.style.fontsize="16px"},!1)}(375,640);

完了,okk,文中所需icon,请自行到阿里icon下载

结尾:项目中需要配置rem。

总结

以上所述是小编给大家介绍的vue cli 3项目使用融云im实现聊天功能的方法,希望对大家有所帮助

上一篇:

下一篇: