Knockout JS,从 websocket 实时更新数据

Knockout JS, live updating data from websocket

我正在尝试从 websocket 加载数据以使用 knockout 和 gaugeMeter.js 在仪表上显示。 我不断收到“无法将绑定多次应用到同一元素”错误。 这是代码 HTML

<div class="GaugeMeter gaugeMeter" id="PreviewGaugeMeter" data-bind="gaugeValue: Percent" data-size=350 data-theme="Orange" data-back="Grey"
  data-text_size="0.4" data-width=38 data-style="Arch" data-animationstep="0" data-stripe="3"></div>

JS

// Bind new handler to init and update gauges.
      ko.bindingHandlers.gaugeValue = {
        init: function(element, valueAccessor) {
            $(element).gaugeMeter({ percent: ko.unwrap(valueAccessor()) });
        },
        update: function(element, valueAccessor) {
          
            $(element).gaugeMeter({ percent: activePlayerData.boost });
            
        }
      };

      // Create view model with inital gauge value 15mph
      // Use observable for easy update.
      var myViewModel = {
        Percent: ko.observable(15)
      };
      
      ko.applyBindings(myViewModel);

activePlayerData.boost 是我从 websocket 获取的数据,需要更新值,它总是显示第一个值,但之后的所有内容都给出错误。 由于我对编码非常陌生,所以我真的迷失了淘汰赛。

下面是您的用例的最小工作示例。您可以 运行 看看它的作用:

// simple gaugeMeter jQuery plugin mockup
$.fn.gaugeMeter = function (params) {
  return this.css({width: params.percent + '%'}).text(params.percent);
}

// binding handler for that plugin
ko.bindingHandlers.gaugeValue = {
  update: function(element, valueAccessor) {
    var boundValue = valueAccessor();
    var val = ko.unwrap(boundValue); // or: val = boundValue();
    $(element).gaugeMeter({ percent: val });
  }
};

// set up viewmodel
var myViewModel = {
  Percent: ko.observable(15)
};
ko.applyBindings(myViewModel);
  
// simulate regular value updates
setInterval(function () {
  var newPercentValue = Math.ceil(Math.random() * 100);
  myViewModel.Percent(newPercentValue);
}, 1500);
div.gaugeMeter {
  background-color: green;
  height: 1em;
  color: white;
  padding: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="gaugeMeter" data-bind="gaugeValue: Percent"></div>

要理解的事情:

  • 只要绑定的可观察对象(即Percent)更改其值,就会调用绑定处理程序的 update 部分。如果没有要初始化的东西,您并不严格需要 init 部分。

  • valueAccessor 为您提供了保存绑定值的东西。通常,但不一定这是可观察的——就像你的情况一样。调用 valueAccessor() 后,您仍然需要打开(也称为“展开”)可观察对象以查看其中的内容。这就是为什么我上面的代码需要两个步骤,valueAccessor()ko.unwrap().

    • 什么时候它不是可观察的? - 您可以自由绑定到视图中的文字值 (data-bind="gaugeValue: 15"),或绑定到不可观察的视图模型当视图模型具有 {basicEfficiency: 15} 时的属性 (data-bind="gaugeValue: basicEfficiency")。在所有情况下,valueAccessor() 都会给你 那个 值,无论是否可观察到。
    • 为什么使用 ko.unwrap(boundValue) 而不是 boundValue() - 前者适用于文字值和可观察值,后者仅适用于可观察值。在绑定处理程序中,支持这两种用例是有意义的。
  • 更新到达后,例如通过 WebSocket,不要尝试重新应用任何绑定或重新初始化任何东西。

    您需要做的就是更改视图模型中相应可观察对象的值。通过调用它来更改可观察值的值:myViewModel.Percent(15); 会将 myViewModel.Percent 设置为 15.

    如果 15 与之前的值不同,可观察对象将负责通知必要的各方(也称为“订阅者”),因此所有必需的操作(例如视图更新)都可以发生。