【问题标题】:How to create a wrapper function for default knockout bindings如何为默认敲除绑定创建包装函数
【发布时间】:2017-10-15 06:14:22
【问题描述】:

我正在展示一个带有淘汰赛的巨大表格结构。用户可以选择通过单击行上的复选框来删除行:

data-bind="checked: row.removed"

问题是表格必须在点击时重新渲染,这在速度较慢的计算机/浏览器上需要一到两秒钟 - 表格在渲染后复选框会更改其状态,因此 UI 感觉没有响应。 我想创建一个包装函数,它与默认的检查绑定执行相同的操作,但另外显示一个加载器符号 - 然后在检查绑定完成其工作后再次隐藏它。比如:

ko.bindingHandlers.checkedWithLoader = {
    update: function(element, valueAccessor, allBindings) {
        loader.show();
        // call knockout's default checked binding here
        loader.hide();
    }
};

这样的事情可能吗?有更好的选择吗?

【问题讨论】:

    标签: javascript knockout.js data-binding


    【解决方案1】:

    如何在自定义绑定中访问其他绑定

    你可以使用ko.applyBindingsToNode:

    ko.applyBindingsToNode(element, { checked: valueAccessor() })
    

    Knockout 的源代码主动公开了此方法 (here),并在其自己的文档页面 (here) 上的示例中引用了它。

    虽然它可能无法解决您处理缓慢渲染的问题......

    处理缓慢的更新

    您还可以在视图模型中创建一个额外的层来构建加载功能:

    this.checked = ko.observable(false);
    
    this.isLoading = ko.observable(false);
    this.showLargeAndSlowTable = ko.observable(false);
    
    this.checked.subscribe(function(isChecked) {
      this.isLoading(true);
      this.showLargeAndSlowTable(isChecked);
      this.isLoading(false);
    }, this);
    

    您需要将ifwith 绑定绑定到showLargeAndSlowTable,并将复选框值绑定到checked

    在某些情况下,您可能需要在设置 loading 可观察对象和注入大型数据集之间强制重新绘制。否则,淘汰赛和浏览器可以将这些更新捆绑到一帧中。

    您可以通过将showLargeAndSlowTableisLoading(false) 放在setTimeout 中来实现这一点,或者通过使用延迟/节流的附加可观察对象,在isLoading 的更改有时间渲染后触发工作:

    function AppViewModel() {
        var self = this;
        
        // The checkbox value that triggers the slow UI update
        this.showLargeTable = ko.observable(false);
        
        // Checkbox change triggers things
        this.showLargeTable.subscribe(updateUI)
        
        // Indicates when we're loading:
        this.working = ko.observable(false);
        this.delayedWorking = ko.pureComputed(function() {
          return self.working();
        }).extend({ throttle: 10 });
        
        // Instead of directly subscribing to `working`, we
        // subscribe to the delayed copy
        this.delayedWorking.subscribe(function(needsWork) {
          if (needsWork) {
            doWork();
            self.working(false);
          }
        });
        
        function updateUI(showTable) {
          if (showTable) {
            self.working(true); // Triggers a slightly delayed update
          } else {
            self.data([]);
          }
        }
        
        // Some data from doc. page to work with
        function doWork() {
          // (code only serves to mimic a slow render)
          for (var i = 0; i < 1499; i++) {
              self.data([]);
              self.data(data.reverse());
          }
        };
        
        var data = [
            { name: 'Alfred', position: 'Butler', location: 'London' },
            { name: 'Bruce', position: 'Chairman', location: 'New York' }
        ];
        
        // Some data to render
        this.data = ko.observableArray([]);
        
    }
    
    
    ko.applyBindings(new AppViewModel());
    .is-loading {
      height: 100px;
      background: red;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .is-loading::after {
      content: "LOADING";
      color: white;
      
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    
    <label>
      <input type="checkbox" data-bind="checked: showLargeTable, disable: working">Show slowly rendered table
    </label>
    
    <table data-bind="css: { 'is-loading': working }">
      <tbody data-bind="foreach: data">
        <tr>
          <td data-bind="text: name"></td>
          <td data-bind="text: position"></td>
          <td data-bind="text: location"></td>
        </tr>
      </tbody>
    </table>
    
    <em>Example based on the <a href="http://knockoutjs.com/documentation/deferred-updates.html">knockout docs</a></em>

    【讨论】:

    • 谢谢!绝对没有办法完全“暂停”淘汰赛的绑定吗?像 ko.pause() / ko.resume() 这样的东西会非常方便。
    • 我会求助于使用 throttlerateLimitdeferred 将更新移动到 javascript 堆栈的末尾。当然,你也可以通过通用的 JavaScript 特性(例如 setTimeout)推迟写入实际的数据绑定 observables。更激进的方法可能是调用 ko.cleanNode 删除绑定并稍后重新应用它们,但我建议不要这样做......
    猜你喜欢
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-16
    • 2011-08-13
    相关资源
    最近更新 更多