将SignalR与Vue.js和Vuex集成

jim*_*mmy 10 javascript signalr vue.js vuex

我们目前正在开发基于vue-cli webpack模板的投票应用程序.由于我们希望以一致且可维护的方式存储和操纵我们的投票状态,因此我们打算使用vuex进行状态管理.前端和后端之间的交互基于websockets,我们希望使用signalr,因为它在之前的项目中已被证明非常好.由于我们是vue.js的新手,我们需要一些建议如何将signalr,vuex和vue.js完美地集成在一起.

我们来描述一下这个场景:

前端从我们的后端获得一个事件来识别投票民意调查是否有效并且可以接收所选答案.一段时间后,我们通知前端结果可用并将其显示给用户.在某些情况下,我们可能会进行另一次投票.重要的是,我们能够在文档被隐藏时断开连接(页面可见性api).

我们的解决方案:

一般来说,我想为此目的实现一个特殊的signal.service.该服务负责建立连接以及通过websockets发送和接收消息.由于我们无法从公共模块对vuex存储执行任何更改,因此我们发现vuex插件是合适的.vuex插件应该包装signalr.

如果我们收到VotingStartEvent,我们将解锁相应的问题并将其显示给用户.如果用户回答了该问题,我们将此问题的新状态(已回答)提交给vuex商店.在我们的插件中,我们订阅了突变,我们将使用此订阅将我们的投票发送到后端.以下片段说明了这个想法:

var plugin = (store) => {
  // ...
  store.subscribe((mutation, state) => {
    console.log('inside subscription');
    // if vote has answered state, call connection.send() to submit the message to the backend
  });

  connection.received((message) => {
    // ...
    var event = parseEvent(message);
    if (event.type === START) {
      store.commit({type: 'voting', item: 'unlocked'});
    }
    // ...
  });
}
Run Code Online (Sandbox Code Playgroud)

这种方法是好的还是你认为还有改进的余地?

小智 5

不需要插件或类似的结构Vue.prototype.$pusher = new Pusher('apiKey').我持有Pusher实例,就像我需要在组件之间共享的任何其他值一样.我在Vue实例方法中初始化Pusher create,就像我需要首先初始化的任何其他库一样.仅仅为了澄清,我故意在组件实例中保存贸易数据,因为它们对于每个实例都是唯一的.不是你所需要的,你必须只存放.

var store = new Vuex.Store({
  state: {
    pusher: null
  },
  mutations: {
    saveInstance(state, instance) {
      state.pusher = instance
    }
  },
  actions: {
    initializePusher ({commit}, apiKey) {
      commit('saveInstance', new Pusher(apiKey))
    }
  }
})

Vue.component('live-price', {
  template: '#live-price',
  props: ['pair'],
  data () {
    return {
      price: 'wait for next trade...',
      channel: null
    }
  },
  created () {
    this.channel = this.$store.state.pusher.subscribe('live_trades_' + this.pair)
    this.channel.bind('trade', data => this.price = data.price)
  }
})

new Vue({
  el: '#app',
  store,
  created () {
    this.$store.dispatch('initializePusher', 'de504dc5763aeef9ff52')
  }
})
Run Code Online (Sandbox Code Playgroud)
[v-cloak] { display: none }
Run Code Online (Sandbox Code Playgroud)
<div id="app">
  <live-price pair="btceur">BITCOIN price in EUR:</live-price>
  <live-price pair="ltceur">LITECOIN price in EUR:</live-price>
  <live-price pair="etheur">ETHEREUM price in EUR:</live-price>
  <live-price pair="xrpeur">RIPPLE price in EUR:</live-price>
</div>

<template id="live-price">
  <p>
    <slot></slot>
    <span v-cloak>{{ price }}</span>
  </p>
</template>

<script src="https://unpkg.com/vue@2.5.3/dist/vue.min.js"></script>
<script src="https://unpkg.com/vuex@3.0.1/dist/vuex.min.js"></script>
<script src="https://js.pusher.com/4.1/pusher.min.js"></script>
Run Code Online (Sandbox Code Playgroud)