Blame view

public/js/plugins/lazy-load.js 6.22 KB
htoooth authored
1 2 3 4
/* eslint-disable */
/**
 * Created by TaoHuang on 2016/10/10.
 */
htoooth authored
5 6 7 8 9

var $ = require('yoho-jquery');

require('./throttle');
htoooth authored
10 11 12 13 14 15 16 17 18 19 20 21
function dataLazyLoad(doc) {

    // 兼容低版本 IE
    Function.prototype.bind = Function.prototype.bind || function(context) {
            var that = this;
            return function() {
                return that.apply(context, arguments);
            };
        };

    // 工具方法 begin
    var Util = {
htoooth authored
22 23
        getElements: function(cls) {
            return $(cls).toArray();
htoooth authored
24 25 26 27 28 29 30 31 32 33 34 35 36
        },
        addEvent: function(ele, type, fn) {
            ele.attachEvent ? ele.attachEvent("on" + type, fn) : ele.addEventListener(type, fn, false);
        },
        removeEvent: function(ele, type, fn) {
            ele.detachEvent ? ele.detachEvent("on" + type, fn) : ele.removeEventListener(type, fn, false);
        },
        getPos: function(ele) {
            var pos = {
                x: 0,
                y: 0
            };
htoooth authored
37 38 39 40
            var offset = $(ele).offset();

            pos.x = offset.left;
            pos.y = offset.top;
htoooth authored
41 42 43 44 45 46 47 48 49 50 51 52

            return pos;
        },
        getViewport: function() {
            var html = doc.documentElement;

            return {
                w: !window.innerWidth ? html.clientHeight : window.innerWidth,
                h: !window.innerHeight ? html.clientHeight : window.innerHeight
            };
        },
        getScrollHeight: function() {
yyq authored
53
            var html = doc.documentElement, bd = doc.body;
htoooth authored
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
            return Math.max(window.pageYOffset || 0, html.scrollTop, bd.scrollTop);
        },
        getEleSize: function(ele) {
            return {
                w: ele.offsetWidth,
                h: ele.offsetHeight
            };
        }
    };
    // 工具方法 end

    return {
        threshold: 0,  // {number} 阈值,预加载高度,单位(px)
        els: null,  // {Array} 延迟加载元素集合(数组)
        fn: null,   // {Function} scroll、resize、touchmove 所绑定方法,即为 pollTextareas()

        evalScripts: function(code) {
htoooth authored
71
            var head = $(".yoho-footer")[0],
htoooth authored
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
                js = doc.createElement("script");

            js.text = code;
            head.appendChild(js, head.firstChild);
            head.removeChild(js);
        },

        evalStyles: function(code) {
            var head = doc.getElementsByTagName("head")[0],
                css = doc.createElement("style");

            css.type = "text/css";

            try {
                css.appendChild(doc.createTextNode(code));
            } catch (e) {
                css.styleSheet.cssText = code;
            }

            head.appendChild(css);
        },

        extractCode: function(str, isStyle) {
            var cata = isStyle ? "style" : "script",
                scriptFragment = "<" + cata + "[^>]*>([\\S\\s]*?)</" + cata + "\\s*>",
                matchAll = new RegExp(scriptFragment, "img"),
                matchOne = new RegExp(scriptFragment, "im"),
                matchResults = str.match(matchAll) || [],
                ret = [];

            for (var i = 0, len = matchResults.length; i < len; i++) {
                var temp = (matchResults[i].match(matchOne) || ["", ""])[1];
                temp && ret.push(temp);
            }
            return ret;
        },

        decodeHTML: function(str) {
            return str.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&")
                .replace(/&lt;/g, '<').replace(/&gt;/g, '>');
        },

        insert: function(ele) {
            var parent = ele.parentNode,
                txt = this.decodeHTML(ele.innerHTML),
                matchStyles = this.extractCode(txt, true),
                matchScripts = this.extractCode(txt);

            parent.innerHTML = txt
                .replace(new RegExp("<script[^>]*>([\\S\\s]*?)</script\\s*>", "img"), "")
                .replace(new RegExp("<style[^>]*>([\\S\\s]*?)</style\\s*>", "img"), "");

            if (matchStyles.length) {
                for (var i = matchStyles.length; i--;) {
                    this.evalStyles(matchStyles[i]);
                }
            }


            // 如果延迟部分需要做 loading 效果
            parent.className = parent.className.replace("loading", "");

            if (matchScripts.length) {
                for (var i = 0, len = matchScripts.length; i < len; i++) {
                    this.evalScripts(matchScripts[i]);
                }
            }
        },

        inView: function(ele) {
            var top = Util.getPos(ele).y
                , viewVal = Util.getViewport().h
                , scrollVal = Util.getScrollHeight()
                , eleHeight = Util.getEleSize(ele).h;

            if (top >= scrollVal - eleHeight - this.threshold && top <= scrollVal + viewVal + this.threshold) {
                return true;
            }

            return false;
        },

        pollTextareas: function() {
            // 需延迟加载的元素已经全部加载完
            if (!this.els.length) {
                Util.removeEvent(window, "scroll", this.fn);
                Util.removeEvent(window, "resize", this.fn);
                Util.removeEvent(doc.body, "touchMove", this.fn);
                return;
            }

            // 判断是否需要加载
            for (var i = this.els.length; i--;) {
                var ele = this.els[i];

                if (!this.inView(ele)) {
                    continue;
                }

                this.insert(ele);
                this.els.splice(i, 1);
            }
        },

        init: function(config) {
            var cls = config.cls;
            this.threshold = config.threshold ? config.threshold : 0;
htoooth authored
180
            this.els = Array.prototype.slice.call(Util.getElements(cls));
htoooth authored
181 182 183
            this.fn = this.pollTextareas.bind(this);

            this.fn();
htoooth authored
184 185

            var _this = this;
htoooth authored
186 187 188
            Util.addEvent(window, "scroll", _this.fn);
            Util.addEvent(window, "resize", _this.fn);
            Util.addEvent(doc.body, "touchMove", _this.fn);
htoooth authored
189
            return this;
htoooth authored
190 191 192 193 194 195 196 197 198
        }
    };
}

module.exports = dataLazyLoad;

/**
 * demo
 * datalazyload.init({
htoooth authored
199
 *     cls: ".datalazyload",    // 需要延迟加载的类,即 textarea 的类名
htoooth authored
200 201 202
 *     threshold: 100          // 距离底部多高,进行延迟加载的阈值
 * });
 */