javascript - 如何为默认 knockout 绑定(bind)创建包装函数

标签 javascript knockout.js data-binding

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

data-bind="checked: row.removed"

问题是表格必须在点击时重新呈现,这在慢速计算机/浏览器上最多需要一到两秒 - 复选框在表格呈现后更改其状态,因此 UI 感觉没有响应。 我想创建一个包装函数,它做与默认检查绑定(bind)相同的事情,但另外显示一个加载器符号 - 然后在检查绑定(bind)完成其工作后再次隐藏它。像这样的东西:

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

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

最佳答案

如何访问自定义绑定(bind)中的其他绑定(bind)

您可以使用ko.applyBindingsToNode:

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

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

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

处理缓慢的更新

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

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 绑定(bind)绑定(bind)到 showLargeAndSlowTable,并将复选框值绑定(bind)到 checked.

在某些情况下,您可能需要在设置 loading observable 和注入(inject)大型数据集之间强制重绘。否则,knockout 和浏览器可以将这些更新捆绑到一个框架中。

您可以通过将 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>

关于javascript - 如何为默认 knockout 绑定(bind)创建包装函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43996795/

相关文章:

android - Kotlin 1.2.50 要求 baseFeatureInfoDir

javascript - import 在 Javascript 中到底是如何工作的

javascript - 多维数组概率

javascript - 使用 Knockout 'foreach' 循环遍历多维数组

javascript - 为什么它以随机顺序初始化这个 Knockout.js 组件?

c# - IValueConverter.Convert 不会在 OneWay 绑定(bind)上被调用

javascript - 使用未知长度字符串拆分 JavaScript 字符串,例如\n

javascript - 全宽 slider ,里面有响应元素

javascript - 在knockout js中动态改变一条线的颜色

c# - 从 XAML 到代码隐藏的数据绑定(bind)