Vue 使用 Vue-socket.io 实现即时聊天应用(vuex管理)
PS:动态地址问题、自动连接问题、vuex管理、学习建议1. 动态socket地址问题最近有小伙伴私信问动态地址问题,今天统一做一下答复,谈谈自己的理解。所谓动态地址,就是请求后端接口,返回一个地址,然后你再连接这个socket.io服务器。如下示例:基础数据 server.json:{"server":"http://localhost:9000"}如上,我定义了一个基础JSON数据,里面有一个
PS:动态地址问题、自动连接问题、vuex管理、学习建议
1. 动态socket地址问题
最近有小伙伴私信问动态地址问题,今天统一做一下答复,谈谈自己的理解。
所谓动态地址,就是请求后端接口,返回一个地址,然后你再连接这个socket.io服务器。如下示例:
基础数据 server.json:
{
"server":"http://localhost:9000"
}
如上,我定义了一个基础JSON数据,里面有一个服务器地址,下面我们通过axios请求这个JSON文件,模拟后端返回数据。
获取socket服务地址 getSocketServer.js
import axios from 'axios'
export const server = axios.get('./server.json');
直接返回一个promise对象,这种情况下,如何获取这个动态地址呢?
main.js:
import VueSocketIO from "vue-socket.io";
import {server} from './getSocketServer'
server.then(res=>{
Vue.use(
new VueSocketIO({
debug: true, // debug调试,生产建议关闭
connection: res.data.server,
})
)
});
这样即可实现动态获取后端路径,进行socket服务器的连接了。
2. 自动连接问题
目前的socket连接,都是直接写在main.js中的,当我们启动vue项目的时候,就自动连接上了socket服务器,这显然在实际的项目中是不允许的。(用户都没有登录系统,输入账号密码,就连接了socket服务,显然是浪费资源的。)
那么,我们如何手动连接(在我们需要连接的时候连接呢?)
// 注册并使用Vue-socket.io
Vue.use(
new VueSocketIO({
debug: true, // debug调试,生产建议关闭
connection: 'http://localhost:9000',
options: { //Optional options,
autoConnect:false,
//autoConnect 通常与 this.$socket.connect()结合使用,表示手动连接socket服务器
}
})
);
添加配置项:options:{autoConnect:false} //表示关闭自动连接
通常,我们前端必有登录页面:
我们只需要在用户输入了用户名之后,手动连接到服务器即可,(连接之后,可以结合我上篇文章说的,将用户名添加到socket对象属性上,便于我们私聊处理信息)
/* 登录 */
login(){
this.$socket.connect();
},
直接给登录按钮绑定login事件,使用this.$socket.connect()手动连接即可!(你还可以对用户输入做校验等操作)
3. vuex管理的socket.io
好的,来到了今天的主要内容:vuex管理socket.io。
3.1 vuex管理模型图
我们可以通过该图示,理解vuex在socket通信中的作用,只要是负责监听socket发布的事件,然后供多组件调用。因为vuex是vue的状态管理仓库,可以实现任意组件间的通信。
举个例子说明:
现在有一个用户 ‘Tom’,想给你发私信,服务器肯定是发布事件:socket.emit('chatPrivate');
有一个聊天组件:chat.vue
还有一个主页组件:first.vue
(如果你在聊天组件,可以监听这个事件,如果你不在呢?应该是主页给出提示:‘有人给你发消息了!’。这个时候,你要在首页组件也监听这个事件,才能收到消息。那同一个监听事件,你写了两次)
如果使用vuex管理,会是怎样?
vuex负责监听这个消息,收到消息了,就赋值给自己的变量=>state.xxx;
其他也需要这个消息的,直接监听state.xxx这个变量的变化即可。
3.2 原生sockets监听实现
如何实现呢?下面我们代码说明,为了给大家直观看出两者的区别,我将两种情况都展示出来:
这是两个简单的组件:first、chat;我们简单监听的welcome事件:
//first.vue:
<script>
export default {
sockets:{
welcome:function(data){
console.log(data)
},
},
}
</script>
//chat.vue:
<script>
export default {
sockets:{
welcome:function(data){
console.log(data)
},
},
}
</script>
3.3 vuex实现
实现了组件监听socket事件,但是一样的代码,写了两遍。下面我们用vuex监听:
import Vue from "vue";
import App from "./App.vue";
import store from './store/index'
import VueSocketIO from "vue-socket.io";
Vue.config.productionTip = false;
// 注册并使用Vue-socket.io
Vue.use(
new VueSocketIO({
debug: false, // debug调试,生产建议关闭
connection: "http://localhost:9000",
vuex: {
store,
actionPrefix: 'SOCKET_',
mutationPrefix: 'SOCKET_'
},
// options: { autoConnect:false, } //Optional options
})
);
引入store文件,在VueSocketIo中添加配置项即可。其中,Prefix是前缀,表示你在定义vuex函数的时候,根据前缀区分普通函数还是socket函数。(这里我们还是打开自动连接)
我们定义简单的vuex文件(index.js)
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
/* 监听服务器事件,直接使用SOCKET_'服务器发布的时间名即可。' */
SOCKET_welcome(state,data){
console.log('vuex-welcome:',data);
},
},
actions: {},
modules: {}
})
运行项目:
vuex已经接收到服务器的事件了。
<template>
<div>
first.vue
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
div{
padding: 10px;
background-color: antiquewhite;
}
</style>
这样,我们first与chat组件里,什么事件都没有监听,通过vuex来接收参数:
改写代码:
state: {
msg:'',
},
mutations: {
/* 监听服务器事件,直接使用SOCKET_'服务器发布的时间名即可。' */
SOCKET_welcome(state,data){
console.log('vuex-welcome:',data);
state.msg=data;
},
},
剩下的事,我们直接监听msg的变化即可!(具体怎么处理返回的数据,就看你实际的业务场景啦)
computed:{
msg(){
return store.state.msg
}
},
结果如下:
注意事项:我们在vuex中使用前缀定义事件 SOCKET_welcome,在服务器端直接写welcome即可。后端能识别SOCKET_前缀的事件。
服务器端:
io.on('connection', function(socket){
console.log('用户已连接');
/* 发布自定义事件 */
socket.emit('welcome','欢迎连接socket.');
/* 每一个socket都会监听一个特殊函数:disconnect 关闭连接 */
socket.on('disconnect',()=>{
console.log('用户关闭了连接');
});
});
通过上面两个示例,可以清楚看到vuex在socket应用中的作用。作为多个组件的通信的使者,vuex取负责监听socket服务器的事件,其他人监听vuex的state变量。
3.2 为什么不用vuex发布事件?
或许有人会疑惑,vuex管理,为何只监听,不发布呢?就是vuex充当所有中间角色,既能监听事件,也能发布事件,vue组件想要和服务器通信,只要监听vuex state数据和commit()veux事件即可。如下图
想要解答这个问题,我们要了解清楚你的业务场景了。
1. 给socket服务器发送数据,可能两个地方的数据相同嘛?(发布事件:emit 其实可以理解为给服务器发送数据)比如chat.vue,发送实际的聊天信息;你可能在first.vue中也发送相同的数据吗?
emit(Event,Params)事件的参数具有特殊性,不具备所有组件都共享,所以不需要将发布事件也放到vuex中管理;
2. 我们通过 this.$socket.emit() 发布事件,这个语句能在vuex中使用吗?
/* 监听事件 */
socket.on('test',data=>{
console.log('test',data)
});
我们监听一个测试事件;
在vuex中定义:
mutations: {
/* 监听服务器事件,直接使用SOCKET_'服务器发布的时间名即可。' */
SOCKET_welcome(state,data){
console.log('vuex-welcome:',data);
state.msg=data;
},
/* 测试发布事件 */
vuexEmit(state,data){
this.$socket.emit('test','vuextest');
},
},
chat.vue组件中,给一个按钮绑定事件:
methods: {
test(){
store.commit('vuexEmit');
}
},
结果如下:
在vuex中是无法识别this.$socket.emit()。
3.3 如何处理 vuex.state
如果真的有需求,说组件发布事件被监听了,需要修改其他组件的内容,你可以使用分开的写法,也比较清晰。
举个例子:
chat.vue是专门处理聊天的组件,而first.vue是首页组件。有人给你发送消息,首页要显示几条未读。当你到chat组件处理后,首页的未读消息要更新。
vue=>socket;socket=>vuex;vuex=>vue
vue组件发布事件,socket监听后发布事件,vuex监听,修改state数据,引起其他组件的变化。
当然,这只是一个简单的例子,肯定有更好的解决办法;我只是想说明,组件与socket的通信,使用 this.$socket.emit()是最简单的。
这个例子可以使用emit()的回调解决是最简单的;vue发布事件,传一个回调函数过去,服务器处理好了,执行回调,返回数据,再store.commit()修改数据。如下图:
有兴趣的可以尝试一下,回调可以参考:
4. 学习建议
对于socket.io的学习,还是希望能自己敲代码去理解,而不是看了文章就算了。同时,多思考为什么是这样;
这个是某博主的文章,使用io.sockets.sockets就能返回对象集合,为什么呢?你是怎么发现的呢?(关于这个,可以看看我上一篇文章,我不是说谁好谁坏,只是提醒大家,多思考,多尝试,多了解底层框架的原理。)
纸上得来终觉浅,绝知此事要躬行!
(可能自己理解也有错误,欢迎留言指正,下期更新vue-socket.io的实战项目,做一个聊天室,讲完实战项目,这个知识点就结束啦)
从连接、通信、管理、实战,涉及了vue-socket.io 使用的全生命周期,望对大家有帮助。
更多推荐
所有评论(0)