【问题标题】:Capture when all images have loaded (and do something) using KnockoutJS使用 KnockoutJS 在所有图像加载(并执行某些操作)时捕获
【发布时间】:2013-03-16 03:39:28
【问题描述】:

我目前有一个基本实现,可以捕获所有图像的加载时间,但我对代码、可伸缩性以及 UI 和 viewModel 之间的紧密耦合不满意。

我在 viewModel 和 bindingHandler 之外声明了一组 promise,以便每个都可以访问它。 bindingHandler 会将每个未解析的 promise 推送到数组中,并且 init 函数将等待数组接收到所有已解析的 promise。一旦发生这种情况,就会调用一个为所有图像设置统一高度的函数。

这是用户界面:

<ul data-bind="foreach: movies">
    <li>
        <div class="image">
            <img data-bind="imageLoad: { src: posters.Detailed, alt: title }"/>
        </div>
    </li>
</ul>

对方:

function ViewModel() {
    var self = this;
    self.movies = ko.observableArray([]);

    self.init = function(data) {
        self.isLoading(true);

        self.movies = ko.utils.arrayMap(data, function(item) {
            return new robot.ko.models.Movie(item);
        });

        $.when.apply($, promises).done(function () {
            robot.utils.setThumbnailHeight($('.thumbnails li'), function () {
                self.isLoading(false);
            });
        });
    };
}

ko.bindingHandlers.imageLoad = {
    init: function(element, valueAccessor) {
        var options = valueAccessor() || {};
        var promise = $.Deferred();

        var loadHandler = function() { return promise.resolve; };
        promises.push(promise);

        ko.applyBindingsToNode(element, {
            event: { load: loadHandler },
            attr: { src: options.src, alt: options.alt }
        });     
    }
}

在一个完美的世界中,我的 viewModel 只会向我的 bindingHandler 传递一个回调,但它是动态的,它不需要了解有关 UI 的任何信息,并且 bindingHandler 将能够确定它需要哪个元素调整。我玩弄了某种 deferredObservable 的想法,但最后我只是不高兴在 viewModel 中有这个。我还考虑过在父元素上使用data- 属性来了解实际设置高度的元素,但这似乎很草率。

我觉得我错过了什么。

所以,我在问,有什么更好的方法来实现这一点,允许松散耦合和可扩展性,这样我就不必专门告诉 UI(尽可能多地)做什么以及何时做,来自我的 viewModel?

【问题讨论】:

  • 为什么投反对票,请解释一下
  • 我也考虑过在父元素上使用 data- 属性来了解实际设置高度的元素,但这似乎很草率。 为什么?恕我直言,这是唯一正确的方法。
  • 您可以在绑定处理程序中访问您的整个虚拟机,为什么不能做您的完美世界示例?如果要实现松耦合,可以制作特定于域的处理程序。还有,你为什么要等到所有图像都完成后才设置它们的高度?
  • 图像正在从外部域加载。它们需要不同的时间来加载。一旦它们全部加载完毕,我需要为周围的父级设置一个高度,以便它们是统一的。我只是在 css3 中这样做。

标签: javascript knockout.js jquery-deferred


【解决方案1】:

在处理它的 foreach 范围内使用自定义绑定。例如:

<ul data-bind="foreach: movies, uniformHeight: movies">
    <li>
        <div class="image">
            <img data-bind="imageLoad: { src: posters.Detailed, alt: title }"/>
        </div>
    </li>
</ul>

基于数据的方法

根据 ViewModel 的形状做出假设 - 具体来说,假设 Promise 的状态反映了加载图像的实际状态。 bindingHandler 可能看起来像这样:

ko.bindingHandlers.uniformHeight = {
  init: function(element, valueAccessor) {
      //assume valueAccessor contains an array of promises
      $.when.apply($, valueAccessor()()).done(function () {
            robot.utils.setThumbnailHeight($(element).find('.thumbnails li'), function () {
                self.isLoading(false);
            });
      });
  }
};

这可能需要围绕您如何处理 robot.ko.models.Movie 中的逻辑进行更多重组,但根据您发布的内容,没什么大不了的。

基于资源的方法

需要更多管道,但最终可能会更可靠。

您的外部uniformHeight 绑定可以在bindingContext 上注册自己,并等待子imageLoad 绑定每次都引发一个事件来通知图像已加载;当它们返回时积累高度,可能会反弹。

【讨论】:

  • 这看起来很有希望。谢谢雷克斯。我现在的工作很忙,所以可能需要一周左右的时间才能开始实施并回答问题。
猜你喜欢
  • 2023-03-03
  • 2012-02-14
  • 1970-01-01
  • 2015-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-26
  • 2019-01-22
相关资源
最近更新 更多