视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Vue Cli 3项目使用融云IM实现聊天功能的方法
2020-11-27 21:58:26 责编:小采
文档


介绍:前台使用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 的音频 base
 break;
 case RongIMClient.MessageType.ImageMessage:
 // message.content.content => 图片缩略图 base
 // message.content.imageUri => 原图 URL
 break;
 case RongIMClient.MessageType.LocationMessage:
 // message.content.latiude => 纬度
 // message.content.longitude => 经度
 // message.content.content => 位置图片 base
 break;
 case RongIMClient.MessageType.RichContentMessage:
 // message.content.content => 文本消息内容
 // message.content.imageUri => 图片 base
 // 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,0);

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

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

总结

以上所述是小编给大家介绍的Vue Cli 3项目使用融云IM实现聊天功能的方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

下载本文
显示全文
专题