knockout.js 删除“展开”子脚本的“if”绑定

5jvtdoz2  于 2022-11-10  发布在  其他
关注(0)|答案(3)|浏览(167)

knockoutjs if绑定可用于根据条件显示或隐藏某些HTML。
然而,在knockout有机会应用绑定之前,浏览器仍然会“看到”并解析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绑定,再加上我真的会认为别人已经完成了这一点。
所以如果有人已经做过了,或者做起来相对简单,我认为这会非常有用。

r8xiu3jd

r8xiu3jd1#

在回答之前:我真的不认为需要这样一个标记。但我会尽力帮助没有疑问 * 为什么 * 你想这样做,因为你描述:
您要使用的标记如下:

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

浏览器不会查看内容,但knockout * 会 * 将数据绑定应用于此类型的节点:一个好的开始。
我想我们要做的事情可以归结为:
1.一旦if绑定值返回true,就用div替换script标记
1.一旦div在文档中,就应用原始的if数据绑定。
因此,我编写了一个自定义绑定处理程序来完成这两件事。

  • 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 };
}

一个(有希望的)工作示例:
第一个

emeijp43

emeijp432#

使用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>

在视图模型中

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>

在视图模型中

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);
a0zr77ik

a0zr77ik3#

这是永远的老,但如果您只是试图隐藏内容,直到呈现绑定,那么您不需要隐藏它在一次性模板。
相反,只要把你隐藏的东西放在一个<div style="display: none" data-bind="visible: true">中,直到应用了敲除绑定,它才会显示出来。

相关问题