使用Knockout和jQuery的Lazyload图像

art*_*ung 9 javascript jquery lazy-loading knockout.js

我有一个使用knockout构建的图像密集型网站并包含jQuery.

这些是在foreach循环中:

<!-- ko foreach: {data: categories, as: 'categories'} -->
<!-- Category code -->
<!-- ko foreach: {data: visibleStations, as: 'stations'} -->
<!-- specific code -->
<img class="thumb lazy" data-bind="attr: { src: imageTmp,
                                           'data-src': imageThumb,
                                           alt: name,
                                           'data-original-title': name },
                                   css: {'now-playing-art': isPlaying}">
<!-- /ko -->
<!-- /ko -->
Run Code Online (Sandbox Code Playgroud)

所以基本上当我创建这些元素时,imageTmp是一个计算的observable,它返回一个临时url,并且imageThumb被设置为来自CDN的真实url.

我也有这段代码,称之为Lazy Sweeper:

var lazyInterval = setInterval(function () {
    $('.lazy:in-viewport').each(function () {
        $(this).attr('src', $(this).data('src')).bind('load', function(){
            $(this).removeClass('lazy')
        });
    });
}, 1000);
Run Code Online (Sandbox Code Playgroud)

该代码将查找视口中的这些图像(使用自定义选择器仅在屏幕上查找图像),然后将其src设置为data-src.

我们想要的行为是避免加载用户看不到的jillion(呃,实际上是几百)的开销.

我们看到的行为是,在第一次加载时,看起来像以后ko.applyBindings()被称为懒惰清扫器被破坏,我们看到图像恢复到默认图像.然后扫地机重新运行,我们看到它们再次显示.

我们不清楚如何以更加淘汰的方式实现这一目标.

思考?见解?想法?


我在twitter上得到了一个答案,提到了一个不同的延迟加载库.这没有解决问题 - 问题是不了解DOM和ko表示如何交互以设置延迟加载.我相信我需要的是一个更好的方法来思考创建一个设置的淘汰模型的问题imageTmp,并根据它是否在视口中响应延迟imageThumb加载,然后加载模型一次(真实图像).

jan*_*oeh 11

更新:现在有一个工作示例.

我的方法是:

  • 让你的模型(站点)决定图像URL是什么 - 临时或真实的,就像你已经做的那样
  • 有一个绑定,其工作是处理DOM - 设置该图像源和处理load事件
  • 限制懒惰的扫地机只是提供"你现在可见"的信号

视图模型

  1. 添加showPlaceholder包含我们州的标志:

    this.showPlaceholder = ko.observable(true);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 添加一个计算的observable,它始终返回当前正确的图像URL,具体取决于该状态:

    this.imageUrl = ko.computed(function() {
      return this.showPlaceholder() ? this.imageTemp() : this.imageThumb();
    }, this);
    
    Run Code Online (Sandbox Code Playgroud)

现在showPlaceholder,只要图像加载,我们所要做的就是设置为false.更多关于这一点.

绑定

我们的绑定工作是设置<img src>每当计算的imageUrl更改.如果src是真实图像,则应lazy在加载后删除该类.

  ko.bindingHandlers.lazyImage = {
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
      var $element     = $(element),
          // we unwrap our imageUrl to get a subscription to it,
          // so we're called when it changes.
          // Use ko.utils.unwrapObservable for older versions of Knockout
          imageSource  = ko.unwrap(valueAccessor());

      $element.attr('src', imageSource);

      // we don't want to remove the lazy class after the temp image
      // has loaded. Set temp-image-name.png to something that identifies
      // your real placeholder image
      if (imageSource.indexOf('temp-image-name.png') === -1) {
        $element.one('load', function() {
          $(this).removeClass('lazy');
        });
      }
    }
  };
Run Code Online (Sandbox Code Playgroud)

懒惰的清扫工

所有这一切需要做的是给我们的viewmodel提示它现在应该从占位符切换到真实图像.

ko.dataFor(element)ko.contextFor(element) 助手功能给我们访问无论是对来自外部的DOM元素的约束:

var lazyInterval = setInterval(function () {
    $('.lazy:in-viewport').each(function () {
      if (ko.dataFor(this)) {
        ko.dataFor(this).showPlaceholder(false);
      }
    });
}, 1000);
Run Code Online (Sandbox Code Playgroud)