淘汰赛'如果'绑定'展开'一个儿童剧本

时间:2016-06-30 00:08:10

标签: knockout.js

knockoutjs if绑定可用于根据条件显示或隐藏某些HTML。

然而,浏览器仍然会看到'并且在挖掘有机会应用绑定之前解析if绑定内的任何内容。如果内容是图像,则即使将立即隐藏该图像,也可以由浏览器下载该图像。

这可能是移动设备上的问题。

我意识到解决这个问题的一种方法是在图像标签上使用数据绑定,这不会设置源,直到knockout运行绑定:

 <img data-bind="attr: {'src': .....}"/>

出于这个问题的目的,我不想这样做(内容比单个图像复杂得多)。所以另一种解决方案是在 if绑定中使用模板绑定,如下所示:

 <!-- ko if: model.banner() == 'cat' -->

    <script type="text/html" id="cat_header">
        <figure>
            <img src="https://largeimages.com/cat.jpg" width="1920" height="1080">
        </figure>
    </script>

    <!-- ko template: { name: 'cat_header' } --><!-- /ko -->

<!-- /ko -->

浏览器会忽略script标记,因此图像不会被下载,直到应用绑定并呈现模板实例。

这很好用,但我觉得有点笨拙。

我真正喜欢做的事情是使用新的绑定更简单的方法,该绑定会自动从脚本标记中解开模板:

 <!-- ko if2: model.banner() == 'cat' -->

    <script type="text/html">
        <figure>
            <img src="https://largeimages.com/cat.jpg" width="1920" height="1080">
        </figure>
    </script>

 <!-- /ko -->

或者这可能更短:

    <script type="text/html" data-bind="if2: model.banner() == 'cat'">
        <figure>
            <img src="https://largeimages.com/cat.jpg" width="1920" height="1080">
        </figure>
    </script>

我只是没有足够的淘汰技能才能写出if2绑定,而且我真的以为其他人已经做过了。

所以,如果有人已经这样做了,或者做起来相对简单,我认为它会非常有用。

3 个答案:

答案 0 :(得分:1)

使用ko模板实际上是一个好主意,尽管它应该更有可能用于渲染重复使用的html的某些部分,而不仅仅是一次。那个说法,我会使模板更通用(我想你也可能想要为其他图像使用类似的模板),所以它接受一个js类代表我们在这种情况下说一个图像。

function AnimalImage(){
    var self = this;
    self.imageUrl = null;
    // plus any other attributes you may want to specify for the image

    self.init = function(imageUrl){
        self.imageUrl = imageUrl;
    }
} 

<script type="text/html" id="animal_header">
    <figure>
        <img data-bind="attr: {'src': imageUrl}" width="1920" height="1080">
    </figure>
</script>

然后,如果您想要显示多个图像,可以在模板绑定中使用'foreach'参数,该参数接受与模板绑定的对象的observableArray

<div data-bind='template: { name: 'animal_header', foreach: animals }'>                                       
</div>
在viewmodel中

self.animals = ko.observableArray();

var cat = new AnimalImage();
cat.init("https://largeimages.com/cat.jpg");
self.animals.push(cat);

var chicken = new AnimalImage();
chicken.init("https://largeimages.com/chicken.jpg");
self.animals.push(chicken);

或者多次将模板用于单个对象

<div data-bind='template: { name: 'animal_header', data: cat }'>                                       
</div>
<div data-bind='template: { name: 'animal_header', data: chicken }'>                                       
</div>
在viewmodel中

self.chicken = ko.observable();
self.cat = ko.observable();

var cat = new AnimalImage();
cat.init("https://largeimages.com/cat.jpg");
self.cat(cat);

var chicken = new AnimalImage();
chicken.init("https://largeimages.com/chicken.jpg");
self.chicken(chicken);

答案 1 :(得分:0)

在回答之前:我并不真正看到需要这样的标记。但我会尝试提供帮助,而不会质疑为什么你想要按照你所描述的那样去做:

您要使用的标记是:

<script type="text/html" data-bind="if2: model.banner() == 'cat'">
    <figure>
        <img src="https://largeimages.com/cat.jpg" width="1920" height="1080">
    </figure>
</script>

浏览器不会查看内容,但是淘汰应用数据绑定到这种类型的节点:一个良好的开端。

我认为我们尝试做的事情归结为:

  1. if绑定值返回true后,替换div的脚本标记
  2. div在文档中后,应用原始if数据绑定。
  3. 所以我编写了一个自定义绑定处理程序来完成这两件事。

    1。等到绑定的值第一次返回true:

     init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
      var initialized = false;
    
      ko.computed(function() { 
        if (!initialized && ko.unwrap(valueAccessor())) {
    

    2。将脚本节点的内容复制到虚拟div

          var scriptTag = element;
          var replacementDiv = document.createElement("div");
          replacementDiv.innerHTML = scriptTag.innerHTML;
    

    3。将原始绑定应用于我们的虚拟div而不是脚本节点

          ko.bindingHandlers.if.init.call(null, 
            replacementDiv, valueAccessor, allBindings, viewModel, bindingContext);
    

    4。将虚拟div注入DOM并删除脚本节点

          scriptTag.parentElement.replaceChild(replacementDiv, scriptTag);
    

    5。总结

          initialized = true;
        }
      }, null, { disposeWhenNodeIsRemoved: element });
    
      return { controlsDescendantBindings: true };
    }
    

    一个(希望)工作的例子:

    &#13;
    &#13;
    ko.bindingHandlers.if2 = {
      init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var initialized = false;
    
        ko.computed(function() {
          if (!initialized && ko.unwrap(valueAccessor())) {
            var scriptTag = element;
            var replacementDiv = document.createElement("div");
            replacementDiv.innerHTML = scriptTag.innerHTML;
    
            ko.bindingHandlers.if.init.call(null, replacementDiv, valueAccessor, allBindings, viewModel, bindingContext);
    
            scriptTag.parentElement.replaceChild(replacementDiv, scriptTag);
            initialized = true;
          }
        }, null, {
          disposeWhenNodeIsRemoved: element
        });
    
        return {
          controlsDescendantBindings: true
        };
      }
    }
    
    ko.applyBindings({
      toggled: ko.observable(false)
    })
    &#13;
    img {
      max-width: 300px
    }
    &#13;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    <script type="text/html" data-bind="if2: toggled">
      <img src="https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_March_2010-1.jpg">
    </script>
    <div data-bind="text: toggled"></div>
    <button data-bind="click: toggled.bind(null, !toggled())">toggle</button>
    &#13;
    &#13;
    &#13;

答案 2 :(得分:0)

这是永远古老的方法,但是如果您只想隐藏内容直到呈现绑定,那么就不需要将其隐藏在一次性模板中。

相反,只需将您隐藏的内容放在中即可。在应用剔除绑定之前,它不会显示。