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查看,这里就不介绍了。

 

你可能感兴趣的:(knockout)