首页 > 编程 > JavaScript > 正文

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

2019-11-19 11:44:53
字体:
来源:转载
供稿:网友

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

效果如图(PC+移动):

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

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

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

二、引入融云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.xxxVue.config.productionTip = falsenew 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实现聊天功能的方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表