从 websocket 侦听器发出全局事件 [英] Emitting global events from websocket listener
问题描述
我想为一个项目做出贡献 - 它是用 Vue 编写的,我是 Vue 的初学者.
我有两个组件 - Setup
和 MainApp
两者都需要根据来自 websocket 的不同消息更新一些状态.一些 websocket 消息会影响前者,一些会影响后者.
Vue 不知道服务,所以我想我只是创建一个自定义组件,带有空的 .在那里实例化 websocket,然后每次在侦听器中出现新消息时发出
this.emit()
.
其他两个组件都会监听发出的信息并且能够做出反应.
不幸的是,我无法让 websocket 组件工作.
main.js:
从'./WsService.vue'导入Ws;//其他进口const 路由 = [//路由]const 路由器 = 新的 VueRouter({路线//`routes: routes` 的缩写})const app = new Vue({路由器}).$mount('#app')//我认为这是实例化我的 webSocket 服务的方法:const WsService = 新的 Vue({el: '#WsService',组件:{ Ws }});
index.html
<div id="应用程序"><div id="WsService"></div><router-link to="/setup">设置</router-link><router-link to="/main-app">主应用程序</router-link><路由器视图></路由器视图>
<script src="/dist/demo-app.js"></script>
websocket服务":
模板><脚本>const PORT_LOCAL = 9988;var ws = new WebSocket("ws://localhost:" + PORT_LOCAL);ws.onopen = 函数(){ws.send('{"jsonrpc":"2.0","id":"reg","method":"reg","params":null}');};ws.onerror = 函数(e){console.log("WebSocket 连接出错!");控制台日志(e);};导出默认{数据() {返回 {}},创建(){var self = this;ws.onmessage = 函数(米){var msg = JSON.parse(m.data);开关(msg.id){//地址请求结果案例reg":self.$emit("reg_received", msg.result);休息;案例发送":self.$emit("send_received", msg.result);休息;案例订阅":self.$emit("subscribe_received", msg.result);休息;默认:控制台日志(味精);休息;}}},方法: {},发送(ID,方法,参数){ws.send('{"jsonrpc":"2.0","id":"' + id + '","method":"' + method + '","params":null}');}}}
例如从主应用发送(这似乎有效):
import WsSvc from './WsService.vue';导出默认{数据() {//},订阅() {let jsonrpc = "jsonrpc 字符串";WsSvc.send(jsonrpc);}}
听emit
:
导出默认 {数据() {//},创建(){this.$on("reg_received", function(result){//对结果做 smth});}}
使用这种配置,created
钩子实际上永远不会被调用 - 因此我永远不会点击 onmessage
侦听器.我认为拥有自定义组件的原因是我可以访问 emit
函数.
感觉我让它变得比它应该的更复杂,但我还没有设法把它做好.解决方案不需要遵循这种方法.
在这种情况下不需要特定于套接字的组件.我过去在几个项目中所做的是实现一个 API 或存储对象来处理套接字消息,然后将该 API 或存储导入到需要它的组件中.另外在类似的答案中,我展示了如何将 WebSocket 与 Vuex 集成.
这是一个示例,它结合了使用 Vue 作为事件发射器的概念和可以导入任何组件的 Web 套接字.组件可以订阅和收听它想收听的消息.以这种方式包装套接字将原始套接字接口抽象化,并允许用户以更典型的 Vue 方式处理 $on/$off 订阅.
Socket.js
从vue"导入Vueconst socket = new WebSocket("wss://echo.websocket.org")const 发射器 = 新 Vue({方法:{发信息){if (1 === socket.readyState)套接字.发送(消息)}}})socket.onmessage = 函数(味精){发射器.$emit("message", msg.data)}socket.onerror = 函数(错误){发射器.$emit("错误", 错误)}导出默认发射器
这是在组件中使用该代码的示例.
App.vue
<ul><li v-for="消息中的消息">{{信息}}模板><脚本>从./socket"导入套接字导出默认{名称:'应用',数据(){返回 {消息:[]}},方法:{处理消息(味精){this.messages.push(msg)}},创建(){Socket.$on("message", this.handleMessage)},beforeDestroy(){Socket.$off("message", this.handleMessage)}}
这是一个工作示例.
I want to contribute to a project - it's written in Vue, and I am a beginner in Vue.
I have two components - Setup
and MainApp
Both will need to update some state based on different messages from the websocket. Some websocket messages will affect the former, some the latter.
Vue doesn't know services, so I thought I'd just create a custom component, with empty <template>
. instantiate the websocket there and then issue an this.emit()
every time a new message occurs in the listener.
Both other components would listen to the emits and would be able to react.
Unfortunately, I can't get the websocket component to work.
main.js:
import Ws from './WsService.vue';
//other imports
const routes = [
//routes
]
const router = new VueRouter({
routes // short for `routes: routes`
})
const app = new Vue({
router
}).$mount('#app')
//I thought this to be the way to instantiate my webSocket service:
const WsService = new Vue({
el: '#WsService',
components: { Ws }
});
index.html
<body>
<div id="app">
<div id="WsService"></div>
<router-link to="/setup">Setup</router-link>
<router-link to="/main-app">Main App</router-link>
<router-view></router-view>
</div>
<script src="/dist/demo-app.js"></script>
</body>
the websocket "service":
<template>
</template>
<script>
const PORT_LOCAL = 9988;
var ws = new WebSocket("ws://localhost:" + PORT_LOCAL);
ws.onopen = function() {
ws.send('{"jsonrpc":"2.0","id":"reg","method":"reg","params":null}');
};
ws.onerror = function(e) {
console.log("error in WebSocket connection!");
console.log(e);
};
export default {
data() {
return {
}
},
created() {
var self = this;
ws.onmessage = function(m) {
var msg = JSON.parse(m.data);
switch(msg.id) {
// result for address request
case "reg":
self.$emit("reg_received", msg.result);
break;
case "send":
self.$emit("send_received", msg.result);
break;
case "subscribe":
self.$emit("subscribe_received", msg.result);
break;
default:
console.log(msg);
break;
}
}
},
methods: {
},
send(id, method, params) {
ws.send('{"jsonrpc":"2.0","id":"' + id + '","method":"' + method + '","params":null}');
}
}
}
</script>
Send for example from main app (this seems to work):
import WsSvc from './WsService.vue';
export default {
data() {
//
},
subscribe() {
let jsonrpc = "the jsonrpc string";
WsSvc.send(jsonrpc);
}
}
Listening to emit
:
export default {
data() {
//
},
created() {
this.$on("reg_received", function(result){
//do smth with the result
});
}
}
Wit this configuration, the created
hook actually never gets called - and thus I'll never hit the onmessage
listener. The reason to have a custom component I thought was that I would have access to the emit
function.
It feels I am making it more complicated than it should be but I haven't managed yet to get it right. The solution doesn't need to follow this approach.
There's no need for a socket specific component in this case. What I have done in the past on a couple projects is implement an API or store object that handles the socket messages and then import that API or store into the components that need it. Also in a similar answer, I show how to integrate a WebSocket with Vuex.
Here is an example that combines the concept of using Vue as an event emitter with a web socket that can be imported into any component. The component can subscribe and listen to the messages it wants to listen to. Wrapping the socket in this way abstracts the raw socket interface away and allows users to work with $on/$off subscriptions in a more typically Vue fashion.
Socket.js
import Vue from "vue"
const socket = new WebSocket("wss://echo.websocket.org")
const emitter = new Vue({
methods:{
send(message){
if (1 === socket.readyState)
socket.send(message)
}
}
})
socket.onmessage = function(msg){
emitter.$emit("message", msg.data)
}
socket.onerror = function(err){
emitter.$emit("error", err)
}
export default emitter
Here is an example of that code being used in a component.
App.vue
<template>
<ul>
<li v-for="message in messages">
{{message}}
</li>
</ul>
</template>
<script>
import Socket from "./socket"
export default {
name: 'app',
data(){
return {
messages: []
}
},
methods:{
handleMessage(msg){
this.messages.push(msg)
}
},
created(){
Socket.$on("message", this.handleMessage)
},
beforeDestroy(){
Socket.$off("message", this.handleMessage)
}
}
</script>
And here is a working example.
这篇关于从 websocket 侦听器发出全局事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!