WeX5数据绑定:customBinding自定义绑定

优质
小牛编辑
116浏览
2023-12-01

自定义绑定(Custom Binding)允许我们通过代码实现自定义绑定规则,从而完成更高级的业务需求。

示例代码

//.js片段
justep.Bind.bindingHandlers.yourBindingName = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
    // This will be called when the binding is first applied to an element
    // Set up any initial state, event handlers, etc. here
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) { 

   // This will be called once when the binding is first applied to an element,
   // and again whenever any observables/computeds that are accessed change
  // Update the DOM element based on the supplied values here.
 };

在自定义绑定的方法中,我们需要向ko.bindingHandlers中添加一个绑定的名称,然后在里面实现init和update方法。从代码结构上来看,实现自定义绑定(custom Binding)并不复杂。下面我们来看一下init和update方法:

init:初始化方法,在DOM绑定时候被调用一次,并且只被调用一次。init方法有两个常用的场景

  • 为DOM设置初始化状态
  • 注册一些事件。例如我们需要在input改变的时候来同步数据到ko的ViewModel中,这个时候就需要在init的时候注册事件。

如果没有这些需要初始化一次的要求,那么init方法是不需要定义的(在init方法执行完成之后,ko会使用相同的参数调用update方法)。

update:update方法会在init方法执行完成之后执行,并且在监视属性或其他依赖属性(observables/computeds)发生改变的时候被调用来更新界面。update方法更常用一些。

下面是一个完整的例子:

//.W片段
<div bind-slideVisible="giftWrap" bind-slideDuration= "600">You have selected the option</div>
<label><input type="checkbox" bind-checked="giftWrap" /> Gift wrap</label>

//.js片段
justep.Bind.bindingHandlers.slideVisible = {
 update: function (element, valueAccessor, allBindings) {
 // First get the latest data that we're bound to
 var value = valueAccessor();

 // Next, whether or not the supplied model property is observable, get its current value
 var valueUnwrapped = justep.Bind.unwrap(value);

 // Grab some more data from another binding property
 var duration = allBindings.get('slideDuration') || 400; // 400ms is default duration unless otherwise specified

 // Now manipulate the DOM element
 if (valueUnwrapped == true)
 $(element).slideDown(duration); // Make the element visible
 else
 $(element).slideUp(duration); // Make the element invisible
 }
};

 var Model = function(){
 this.callParent();
 this.giftWrap=justep.Bind.observable(true);
 };

如何支持虚拟节点?

ko的if、foreach等绑定支持虚拟节点,那么我们如何让自己的代码来支持虚拟节点呢?

首先,我们自定义一个绑定:

//.js片段
justep.Bind.bindingHandlers.randomOrder = {
    init: function (elem, valueAccessor) {
        // Pull out each of the child elements into an array
        var childElems = [];
        while (elem.firstChild)
            childElems.push(elem.removeChild(elem.firstChild));

        // Put them back in a random order
        while (childElems.length) {
            var randomIndex = Math.floor(Math.random() * childElems.length),
                chosenChild = childElems.splice(randomIndex, 1);
            elem.appendChild(chosenChild[0]);
        }
    }
};

在DOM节点中的用法

<div bind-randomOrder="true">
    <div>First</div>
    <div>Second</div>
    <div>Third</div>
</div>

如果我们想要在虚拟节点中使用,例如:

<!-- justep.Bind randomOrder: true -->
    <div>First</div>
    <div>Second</div>
    <div>Third</div>
<!-- /justep.Bind-->

那么,我们需要在KO中注册,允许我们的自定义绑定用在虚拟节点中:

justep.Bind.virtualElements.allowedBindings.randomOrder = true;

接下来对我们的自定义绑定进行修改:

justep.Bind.bindingHandlers.randomOrder = {
    init: function (elem, valueAccessor) {
        // Build an array of child elements
        var child =justep.Bind.virtualElements.firstChild(elem),
            childElems = [];
        while (child) {
           childElems.push(child);
           child =justep.Bind.virtualElements.nextSibling(child);
       }
        // Remove them all, then put them back in a random order
       justep.Bind.virtualElements.emptyNode(elem);
       while (childElems.length) {
          var randomIndex = Math.floor(Math.random() * childElems.length),
              chosenChild = childElems.splice(randomIndex, 1);
      justep.Bind.virtualElements.prepend(elem, chosenChild[0]); } } };

这样一来我们自定义的绑定就能用在虚拟节点中了。