Knockoutjs实战开发:自定义标签支持虚拟元素(Creating custom bindings that support virtual elements)

Knockoutjs的控制流程绑定(比如:if和foreach)不仅仅可以绑定在一个真实的DOM元素上,我们也可以将其绑定到一个虚拟的DOM元素上,这个DOM是由一个特殊语法定义的。比如:

1 <ul> 
2     <li class="heading">My heading</li> 
3     <!-- ko foreach: items --> 
4         <li data-bind="text: $data"></li> 
5     <!-- /ko --> 
6 </ul>

我们自定义的标签也能向上例一样支持虚拟元素,但是,为了使用此功能,我们必须明确的告诉Knockoutjs我们自定义的绑定是支持虚拟元素的,此时我们可以使用ko.virtualElements.allowedBindings方法来通知Knockoutjs。

例1、作为开始,我们首先自定义一个绑定,如下:

 1 <script type="text/javascript">
 2      ko.bindingHandlers.randomOrder = {
 3          init: function (elem, valueAccessor) {
 4              // Pull out each of the child elements into an array 
 5              var childElems = [];
 6              while (elem.firstChild)
 7                  childElems.push(elem.removeChild(elem.firstChild));
 8 
 9              // Put them back in a random order 
10              while (childElems.length) {
11                  var randomIndex = Math.floor(Math.random() * childElems.length),
12                 chosenChild = childElems.splice(randomIndex, 1);
13                  elem.appendChild(chosenChild[0]);
14              }
15          }
16      };
17 </script>

此时我们自定义的绑定在真实的DOM元素中是可以起作用的,下面的元素会按照随机数重新进行排序:

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

而我们自定义的绑定则不会在虚拟DOM元素中起作用。

<!-- ko randomOrder: true --> 
    <div>First</div> 
    <div>Second</div> 
    <div>Third</div> 
<!-- /ko -->

你可能还会获得以下的错误:The binding 'randomOrder' cannot be used with virtual elements。为了让我们自定义的绑定在虚拟DOM元素上起作用,我们可以使用下面的语句来通知Knockoutjs。

ko.virtualElements.allowedBindings.randomOrder = true;

此时,可能不会报错了,但是我们自定义绑定依然没有起作用,这是因为我们使用的编码方式并不能支持虚拟元素,这也就是为什么Knockoutjs会让我们选择性的支持虚拟元素:除非你编写的自定义绑定代码也支持虚拟元素,否则即使你加入上面的话,也不会起作用的。
因此我们将上例中的自定义绑定做如下的修改:

 <script type="text/javascript">
     ko.bindingHandlers.randomOrder = {
         init: function (elem, valueAccessor) {
             // Build an array of child elements 
             alert("bb");
             var child = ko.virtualElements.firstChild(elem),
            childElems = [];
             while (child) {
                 childElems.push(child);
                 child = ko.virtualElements.nextSibling(child);
             }

             // Remove them all, then put them back in a random order 
             ko.virtualElements.emptyNode(elem);
             while (childElems.length) {
                 var randomIndex = Math.floor(Math.random() * childElems.length),
                chosenChild = childElems.splice(randomIndex, 1);
                 ko.virtualElements.prepend(elem, chosenChild[0]);
             }
         }
     };
     ko.virtualElements.allowedBindings.randomOrder = true;
</script>

此时,我们的虚拟标签就可以使用了。此时我们使用ko.virtualElements.firstChild(domOrVirtualElement)代替了domElement.firstChild
此例的完整代码如下:

 1 <script type="text/javascript" src="knockout-2.2.0.js"></script>
 2 
 3 
 4 -------------------------------------
 5 <!-- ko randomOrder: true --> 
 6     <div>First</div> 
 7     <div>Second</div> 
 8     <div>Third</div> 
 9 <!-- /ko -->
10  <script type="text/javascript">
11      ko.bindingHandlers.randomOrder = {
12          init: function (elem, valueAccessor) {
13              // Build an array of child elements 
14              alert("bb");
15              var child = ko.virtualElements.firstChild(elem),
16             childElems = [];
17              while (child) {
18                  childElems.push(child);
19                  child = ko.virtualElements.nextSibling(child);
20              }
21 
22              // Remove them all, then put them back in a random order 
23              ko.virtualElements.emptyNode(elem);
24              while (childElems.length) {
25                  var randomIndex = Math.floor(Math.random() * childElems.length),
26                 chosenChild = childElems.splice(randomIndex, 1);
27                  ko.virtualElements.prepend(elem, chosenChild[0]);
28              }
29          }
30      };
31      ko.virtualElements.allowedBindings.randomOrder = true;
32 </script>
33 
34 <script type="text/javascript">
35     var viewModel = {
36         giftWrap: ko.observable(true)
37     };
38     ko.applyBindings(viewModel);
39 </script>
40 
41 
42 
43   

 虚拟元素的API大家可以点击:http://knockoutjs.com/documentation/custom-bindings-for-virtual-elements.html查看,这里就不介绍了。

原文地址:https://www.cnblogs.com/wukong65/p/2815986.html