懒加载的模块化实现

问题背景:

有时打开一个页面,要很长时间页面才能响应,这是因为通常对于页面响应的JS,需要等待页面的元素上全部加载完毕后,才能执行;
图片加载需要的时间都比较长,对于图片较多的页面设计,如果不对元素进行设置的话,就需要将所有图片加载完后,页面才能响应
这不仅花费时间较长;同时也会浪费流量,可能用户并不需要看后面的许多内容;

懒加载就是针对这种情况的一个解决方法,对于页面上的元素,当进入视野中才进行加载,这样就减少了页面打开加载的时间,同时也节省了不必要的流量。
对于一些需要实时更新内容的元素,也可利用懒加载,在元素进入视野时,再刷新;

场景模拟:

模拟一个场景,既需要加载图片也需要实时更新页面内容


image.png

上半部是需要实时更新文本的部分,每当文本框进入视野时,文本内容会更新;
下方是需要加载的多个图片

1.模块化的实现

页面中不同的模块需要的处理方式不同,文本信息重新进入视野需要刷新内容;但图片即便多次翻动页面进入视野,也不需要重复加载,只需要一次就够了;
所以,为了更好的模块兼容性,使用面向对象的方法来实现懒加载的模块,针对不同的需求,只需要进行相应的实例化,就可以了

function showImg($node) {
    $node.attr('src', $node.attr('data-src'))
}

var Lazy = (function() {
            return {
                realTime: function($targets, callback) {
                    $targets.each(function(idx, target) {
                        new Exposure($(target), false, callback);
                    })
                },

                once: function($targets, callback) {
                    $targets.each(function(idx, target) {
                        new Exposure($(target), true, callback);
                    })
                }
            }
        })()

        Lazy.realTime($('#hello'), function($node) {
            $node.text($node.text() + '123');
        });
        Lazy.realTime($('#world'), function($node) {
            $node.text($node.text() + '456');
        });
        Lazy.once($('.container img'), function($node) {
            showImg($node);
        });

  function Exposure($target, once_check, callback) {
        this.$target = $target;
        this.once_check = once_check;
        this.callback = callback;
        this.loaded = false;
        this.bind();
        this.check();
}

对于不同的模块,通过不同的接口进行实例化,并提供相应的回调来处理模块进入视野后的处理方法;
值得说明的一点是,Lazy提供的接口中,是利用了数组的方法.each,来对每个元素都进行了一次Exposure的对象创建。
这是考虑到对于批量的图片,只需要一次全部选择,即可对内部每一个图片进行实例化了,使用更方便,即便是内部只有一个元素的文本,也可通用,兼容性更好。但缺点是对象的重复创建太多,每个img都创建了一个Exposure对象

2.模块进入视野的判断方法

        Exposure.prototype.isVisible = function($node) {
            var windowHeight = $(window).height();
            var offsetTop = $node.offset().top;
            var nodeHeight = $node.height();
            var scrollTop = $(window).scrollTop();
            if (windowHeight + scrollTop > offsetTop + nodeHeight && scrollTop < offsetTop + nodeHeight) {
                return true
            }

            return false
        }

滚动的高度加上窗口的高度,大于目标到页面顶端的高度,说明进入窗口。
同时,滚动高度小于目标到页面的offsetTop,说明还停留在窗口中,没出去,两个条件都要满足

3.判断元素是否加载过

        Exposure.prototype.isLoaded = function($node) {
            if ($node.attr('loaded')) {
                return true;
            } else {
                $node.attr('loaded', 'true');
                return false;
            }
        }

通过判断元素属性“loaded”,来判断元素是否加载过

源码
演示
可以看到,当反复滚动页面,文本框重新进入窗口后,文本内容改变
在showImg中console.log,在控制台可以看到,当图片加载过一次之后,再滚动页面,load-img-go不再增加

image.png

你可能感兴趣的:(懒加载的模块化实现)