【问题标题】:Integrate SignalR with Vue.js and Vuex将 SignalR 与 Vue.js 和 Vuex 集成
【发布时间】:2018-04-19 23:57:24
【问题描述】:

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

让我们描述一下场景:

前端从我们的后端获取一个事件以识别投票投票处于活动状态并且可以接收选定的答案。一段时间后,我们通知前端结果可用并将其显示给用户。在某些情况下,我们可能会打开另一个投票投票。重要的是我们能够断开连接以防文档被隐藏(页面可见性 api)。

我们的解决方案:

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

如果我们收到 VotingStartEvent,我们将解锁相应的问题并将其显示给用户。如果用户回答了这个问题,我们会将这个问题的新状态(已回答)提交给 vuex 存储。在我们的插件中,我们订阅了突变,我们将使用此订阅将投票发送到后端。下面的 sn-p 说明了这个想法:

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'});
    }
    // ...
  });
}

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

【问题讨论】:

  • 我不能在示例中使用 SignalR,但是如果您愿意,为了获得灵感,我可以在这里写一个实时的工作示例,我如何将另一个 WS 库(Pusher)集成到 Vue 并在Vuex。
  • 不需要插件。当你在 SignalR 中接收到一个事件时,只需调度一个动作。 stackoverflow.com/questions/44333164/vuex-websockets/44336198
  • @WaldemarIce 非常感谢!一个简短的灵感会很棒:)
  • @Bert 感谢您的建议!但在那种情况下,我需要对 store 的引用,并且我更喜欢单独的模块来处理 store 和 signalr。使用 vuex 插件我们可以实现这一点,但我不确定这是否是一个好习惯。
  • 这就是导入/导出的全部内容。在一个模块中定义 SignalR,将 store 导入其中。或者,将它们都定义在单独的模块中,然后将它们都导入到第三个模块中。完全分离关注点。

标签: javascript vue.js signalr vuex


【解决方案1】:

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

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')
  }
})
[v-cloak] { display: none }
<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>

【讨论】:

  • 非常感谢您的示例!这是一种有趣的方法,我们将评估将我们的实例保存在 store 中。
  • @jimmy 不客气 :) 为了澄清起见,我在 Vuex 中持有实例,因为它也只是一个(数据)对象。如果所有共享数据都属于 Vuex,那么... :)
  • 是pusher第三方库,需要一段时间后付费吗?
猜你喜欢
  • 2017-04-14
  • 2019-11-30
  • 1970-01-01
  • 2018-09-13
  • 2017-07-10
  • 2019-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多