我先说我的文件结构和代码类型。应用了vuex的仓库来链接socket IO 和一些全局的方法和参数。至于vuex仓库是怎么使用的我这里就不过多的描述了。
- 在仓库中封装socket IO,链接对话框
这一部分代码,我在 聊天系统/《uniapp中使用socket IO》里面有提到过,此处略过
index.js仓库↓↓
import io from '@hyoga/uni-socket.io';
export default new Vuex.Store({
state: {
isLoad: false,
socket: null,
lineState: false,
clientId: null, //对方
kefuId: null,
target: null, //目标
chatList: [],
msg: null,
action: null,
},
// 计算属性 可以获得参数,第一个是state,第二个是getters(自身) 用户传参(state,getters)=> (id)=>{}
getters: {
getUser: state => state.user,
getToken: state => state.token,
getClientId: state => state.clientId,
getKeFuId: state => state.kefuId,
getTarget: state => state.target,
getChatList: state => state.chatList,
getMsg: state => state.msg,
},
// 动态改变变量值
mutations: {
},
actions: {
connectSocket({
state,
dispatch
}, data) {
const socket = io(conf.socketUrl, {
query: data,
transports: ['websocket'],
timeout: 5000,
});
socket.on('connect', () => {
console.log('ws 已连接');
state.socket = socket
state.lineState = true
// socket.io 唯一连接id,可以监控这个id实现点对点通讯
const {
id
} = socket;
state.clientId = id
const chatPush = (e) => {
uni.$emit('chatPush', e)
}
const noKefu = () => {
uni.$emit('noKefu')
}
socket.on(id, (message, fn) => {
state.msg = message
const action = message.data.action
state.action = action
const data = message.data
console.log('action:', action);
console.log('ws data:', data);
switch (action) {
case 'online':
uni.showToast({
title: "连接成功",
icon: 'none'
})
state.kefuId = message.data.payload.kefuId
break;
case 'no':
uni.showToast({
title: "没有可分配客服",
icon: 'none'
})
noKefu()
if (state.lineState) {
this.dispatch('closeSocket')
}
break;
case 'noline':
uni.showToast({
title: "对方不在线",
icon: 'none'
})
break;
case 'exchange':
// 拿到数据传出去
// console.log(123);
chatPush(data)
break;
}
// 收到服务器推送的消息,可以跟进自身业务进行操作
if (typeof fn === 'function') {
fn('ok')
}
});
});
socket.on('online', (msg) => {
console.log(msg);
});
socket.on('disconnect', () => {
console.log("断开链接");
if (state.lineState) {
this.dispatch('closeSocket')
}
});
socket.on('error', (msg) => {
console.log('ws error', msg);
if (state.lineState) {
this.dispatch('closeSocket')
}
});
},
closeSocket({
state,
dispatch
}) {
const offChat = ((e) => {
uni.$off('chatPush', e)
})
state.lineState === false
offChat()
if (state.socket !== null) {
state.socket.close()
state.socket = null
state.lineState = false
state.target = ''
}
},
//给服务器发送消息
sendMsg({
state,
dispatch
}, data) {
console.log(data);
state.socket.emit('exchange', data)
}
}
})
在index.vue页面中
onLoad() {
//页面初始化的时候就开始调用onPush()方法
this.onPush()
},
methods: {
onPush() {
//使用uni.$on()来监听仓库中接受服务器的消息,并判断发信人和收信人的身份,如果发信人是自己,就不提示消息音。如果发信人是别人,就提示消息音
uni.$on('chatPush', data => {
// console.log(data);
if (this.clientInfoData.userId === data.payload.owner) {
this.target = data.meta.target;
} else {
this.target = data.meta.client;
//当是对方发过来的消息时,发出提示音
const innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;
innerAudioContext.src = '../../static/tone/default.mp3';
innerAudioContext.onPlay(() => {
console.log('开始播放');
});
innerAudioContext.play();
}
// push
this.chatData.push(data);
if (data.payload.kefuId) {
const name = data.payload.kefuId.name ? data.payload.kefuId.name : '小智';
this.subTitle = `客服 ${name}`;
}
this.pullRefresh = true
});
},
}