图片延迟加载demo

Talk is cheap,show me the Code~先上代码,再说心路

/**
 * lazyload demo
 * 
 */
(function($, window, document, undefined) {
    $.fn.Lazyload = function(opts) {
        var elements = this,
            timer = false,
            defaults = {
                data_attribute: 'data-src',
                threshold: 0
            },
            options = $.extend({}, defaults, opts);
        //最初进入页面从所有元素中筛选出在视区内的元素执行任务
        bindEvents();
        //滚动事件停止后视区内的元素执行任务
        $(window).on("scroll", function() {
            if (timer) { clearTimeout(timer); }
            timer = setTimeout(bindEvents, 1000);
        })

        function bindEvents() {
            elements.each(function() {
                var me = this;
                me.loaded = false; //将所有元素标记为  未执行任务,执行过appear()的元素该属性就会标记为true
                if (checkIsInView(me)) {
                    appear(me);
                }
            });
            //将元素列表的更新放到一屏结束后统一更新一次
            var temp = $.grep(elements, function(element) {
                return (!element.loaded);
            })
            elements = $(temp);

        };

        function checkIsInView(element) {
            var isAboveTheView,
                isBelowTheView,
                $window = $(window);

            isAboveTheView = ($(element).offset().top + $(element).height() + options.threshold < $window.scrollTop()) ? true : false;
            isBelowTheView = ($(element).offset().top - options.threshold > $window.scrollTop() + $window.height()) ? true : false;
            if (!isBelowTheView && !isAboveTheView) {
                return true;
            } else {
                return false;
            }
        };

        function appear(element) {
            var data_src = $(element).attr(options.data_attribute);
            $(element).attr("src", data_src);
            element.loaded = true;
        };

    }
})(window.jQuery, window, document);

心路历程&查漏补缺

1、模式的转变

最开始使用了构造函数加原型的混合模式,但是后来发现这样写很有问题(当然很有可能是我掌握不精所致),直接�把这个完整的方法赋给每个元素,不容易将执行完任务的元素从待执行任务的元素列表中移除,所以后来改成了单例模式,然后这个就越看越像是jquery.lazyload.js的极简版。
那么总结下思路的转变过程:

滚动停止后对所有元素都去判断是否在视区,执行相应任务——改为——滚动停止后从待执行任务的元素列表中搜索留在视区内的元素,显示。

另外,在模式转变的过程中函数方法的定义方式也要发生改变,这使得我对原型函数中的对象方法有了进一步的认识。我们都知道在js中一切都是对象,对象方法和对象属性没什么不同,只是前者的值是函数而已,所以原型函数中的对象方法看起来也都是键值对的样子。想访问该属性,当做字符串访问,想调用该方法加(),如:

var person = {
    firstName: "John",
    lastName : "Doe",
    id       : 5566,
    fullName : function() {
       return this.firstName + " " + this.lastName;
    }
};
console.log(person.fullName);//function() { return this.firstName + " " + this.lastName;}
console.log(person.fullName());//John Doe

2、更新元素列表这项工作放到哪儿执行更好?

每个元素的图片被替换之后就立即更新列表,还是这一屏的元素的图片都替换完了之后再统一更新一次?这两者哪个耗时更短?前者是筛选次数执行的多,后者是查找的次数执行的多,个人从理论上分析,筛选是要更耗时的,因为一次筛选过程要查找然后更新新数组(不管其内部用的是数组还是指针都要多几步的,那么对于数组元素的删除、过滤其内部是如何实现的还有待考究)。所以我是在一屏的图片被替换后更新一次元素列表。

这是更新数组的代码:

      var temp=$.grep(elements,function(element){
            return (!element.loaded);//最开始遍历元素的时候给每个元素设置一个属性loaded作为标志位
       })
       elements=temp;

3、添加限制条件:滚动停止后才执行替换图片的任务

这一知识也是听师父介绍的,这个在淘宝无线端有应用。这儿利用setTimeout来判断滚动事件停止,滚动过程中不去加载。(像移动端有区分touchStart,touchEnd事件就不用这么麻烦了)

 $(window).on("scroll", function() {
     if (timer) { clearTimeout(timer); }
     timer = setTimeout(bindEvents, 1000);
 })

最开始的时候把timer定义在了scroll事件里,然后就理所当然的发生里一些不可思议的事情。。。真是粗心大意害死人。

4、获取到文档顶部距离

jquery中获取元素到文档顶部的距离:$().offset().top
当前视口到文档顶部的距离: scrollTop()
原生javascript中只能获取相对父元素的left,top,那么是如何获得距离文档顶部的距离的?
一层层递归到父元素为body

function getOffsetTop(element){
  var actualTop = element.offsetTop;
  var current = element.offsetParent;
  while (current !== null){
    actualTop += current.offsetTop;
    current = current.offsetParent;
  }
  return actualTop;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,825评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • 很多时候我们感到害怕和不想尝试新的挑战,是因为对未知事物的恐惧,第一天的训练强度很大,但今天已经基本适应,或者说从...
    FAB苹果阅读 165评论 0 0
  • 凌乱 潋滟的 唇 闪动的 波光 风卷着 柳絮 如雪 轻坠 瞬间的凝固 从指缝间 旋舞 缠绕 心 不再 跳动 编号:...
    Keya的意识空间阅读 157评论 0 2