从WebSocket监听器发出全局事件

7

我想为一个项目做出贡献,这个项目是用Vue编写的,而我在Vue方面是一个初学者。

我有两个组件 - SetupMainApp

两个组件都需要根据websocket中不同的消息更新一些状态。一些websocket消息会影响前者,一些则影响后者。

Vue不知道服务,所以我想创建一个自定义组件,其中包含空的<template>。在那里实例化websocket,然后每次监听器中发生新消息时发出this.emit()

其他两个组件将侦听发出的信号,并能够做出反应。

不幸的是,我无法使websocket组件正常工作。

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>

WebSocket "服务":

<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>

例如从主应用程序发送(这似乎有效):

 import WsSvc from './WsService.vue';
 export default {
   data() {
     //
   },
   subscribe() {
     let jsonrpc = "the jsonrpc string";
     WsSvc.send(jsonrpc);
   }
 }

听取emit

 export default {
   data() {
     //
   },
   created() {
     this.$on("reg_received", function(result){
       //do smth with the result
     });

   }
 }

使用这个配置,created钩子实际上永远不会被调用,因此我永远不会命中onmessage监听器。我认为要使用自定义组件的原因是我可以访问emit函数。
感觉我正在把它变得比应该的更复杂,但我还没有成功。解决方案不需要遵循这种方法。

"Vue 不知道服务" 这并不完全正确。只需构建您的 API 并将其导入到您想要使用它的组件中即可。这里不需要组件。 - Bert
@Bert 也许你是对的,但问题不在于API,而在于如何从“onmessage”回调并更新其他组件的属性。 - transient_loop
1
这个怎么样?https://codesandbox.io/s/4wp90vvr2w - Bert
@Bert,我并不是完全按照你提供的链接解决了问题,但是你的链接给了我灵感,让我解决了这个问题。如果你想把它作为答案提供,我会接受的。谢谢! - transient_loop
2个回答

13
在这种情况下,不需要一个特定于 socket 的组件。我在之前的一些项目中所做的是实现一个处理 socket 消息的 API 或存储对象,然后将该 API 或存储导入到需要它的组件中。同时,在类似的答案中,我展示了如何将 WebSocket 与 Vuex 集成。
下面是一个示例,结合了使用 Vue 作为事件发射器的概念和可以导入到任何组件的 Websocket。该组件可以订阅并监听它想要监听的消息。通过这种方式包装 socket,可以抽象出原始的 socket 接口,并允许用户以更常见的 Vue 方式使用 $on/$off 订阅。 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

以下是在组件中使用该代码的示例。

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>

这里是一个实际示例


0

嘿,这个对你来说应该更好、更容易

这是我的一个带有 .vue 文件的例子

yourVueFile.Vue

 <template>
// key in your template here
</template>

<script>
export default {
//use the created() option to execute after vue instance is created
  created() {
    let ws = new WebSocket("yourUrl");
    ws.onopen = e => {
      ws.send(
        JSON.stringify({ your json code })
      );

        ws.onmessage = e => {
        let data = JSON.parse(e.data);

// the this.$data get your data() options in your vue instance
            this.$data.dom = data;

      };
    };
  },
  data() {
    return {
       dom: core
    };
  },
  methods: {

  }
};
</script>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接