成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

手摸手-100行代碼自己動手寫個功能完整的圖片懶加載插件

CompileYouth / 1106人閱讀

摘要:景科同學(xué)的想法很簡單,因為本人目前還是一個前端小白,只有通過不斷的寫,不斷的學(xué),在與的相愛相殺中才能更快速的進步。本項目是景科同學(xué)自寫自測,雖然比較簡單,但是不保證沒有隱藏的。所以如果看官同學(xué)發(fā)現(xiàn)還望留言指正,景科同學(xué)在此以示感謝。

本文相對比較初級,為了節(jié)約時間,請小神及其以上級別的同學(xué)直接忽略。

有同學(xué)可能會問:那么多第三方庫,為什么要自己動手寫呢。景科同學(xué)的想法很簡單,因為本人目前還是一個前端小白,只有通過不斷的寫,不斷的學(xué),在與bug的相愛相殺中才能更快速的進步。在證明可行可用之后不僅可以減少項目的第三方依賴,即便出現(xiàn)bug,解決自己代碼的bug也要比解決別人代碼的bug要好過一些。話不多說,且入正題。

一. 基礎(chǔ)結(jié)構(gòu)
手摸手第一步。在第一步,先把基礎(chǔ)結(jié)構(gòu)構(gòu)思搭建一下,以方便后續(xù)擼碼。圖片懶加載本身就不是什么復(fù)雜的實現(xiàn),所以基本結(jié)構(gòu)也比較簡單,無非就是初始化一下參數(shù),容一下錯,綁定幾個函數(shù),實現(xiàn)一下功能而已。具體代碼且往下看:
(function (global, factory) {
    if (typeof exports === "object" && typeof module !== "undefined") {
        module.exports = factory(global)
    } else if (typeof define === "function" && define.amd) {
        define(factory)
    } else {
        global.Lazy = factory(global)
    }
})(this, function () {
    // 全局變量,所有方法在此對象上擴展
    var Lazy = {};
    // 計時器
    var timer = null;
    // 節(jié)流延遲時間
    var delay = 150;
    // 是否開啟節(jié)流
    var debounce = true;
    // 是否開啟圖片懶加載圖片的重載。解釋一下:就是圖片離開懶加載區(qū)域要把圖片狀態(tài)復(fù)原,再次進入懶加載區(qū)域要在視覺上呈現(xiàn)懶加載效果
    // 先呵呵一下這個功能,正常的我肯定想不到這么個抽風(fēng)的需求,誰讓我曾經(jīng)碰到過一個抽風(fēng)的產(chǎn)品經(jīng)理呢,實現(xiàn)不難,這里也順便實現(xiàn)一下
    var unload = false;
    // 回掉函數(shù)
    var callback = function () {};
    // 元素相對于視窗的位置集合
    var boxRect = {};
    /**
    * 判斷目標(biāo)元素是否可見 #1
    * @param {HTMLElement} element
    * @returns {boolean}
    */
    var isHidden = function (element) {};
    /**
     * 判斷目標(biāo)元素是否進入懶加載區(qū)域 #2
     * @param {HTMLElement} element
     * @returns {boolean}
     */
    var canLoadImg = function (element) {};
    /**
     * 節(jié)流函數(shù) #3
     */
    var onDebounceRender = function () {};
    /**
     * 始化方法,外部直接調(diào)用,配置參數(shù)在此接收 #4
     * @param {Object} options
     * @param {String} options.root - 圖片滾動區(qū)域根元素選擇器
     * @param {Number} options.offset - 懶加載閾值,當(dāng)沒有【上下左右】4個值時將以此為準(zhǔn)
     * @param {Number} options.offsetTop - 懶加載閾值【上】
     * @param {Number} options.offsetRight - 懶加載閾值【右】
     * @param {Number} options.offsetBottom - 懶加載閾值【下】
     * @param {Number} options.offsetLeft - 懶加載閾值【左】
     * @param {Boolean} options.debounce - 是否開啟函數(shù)節(jié)流
     * @param {Number} options.delay - 函數(shù)節(jié)流時間閾值
     * @param {Boolean} options.unload - 圖片重載
     * @param {Function} options.callback - 懶加載操作完成時的回掉函數(shù)
     */
    Lazy.init = function(options) {};
    /**
     * 懶加載實現(xiàn) #5
     * @param {HTMLElement} element
     */
    Lazy.render = function(element) {};
    /**
     * 不滿足懶加載條件時銷毀 #6
     */
    Lazy.destroy = function() {};
    // 返回
    return Lazy;
});

由于項目本身并不復(fù)雜,所以基礎(chǔ)的結(jié)構(gòu)也比較簡單,剩下的幾步我們只需要手摸手去做填空題(#1、#2、#3、#4、#5、#6)就好了。so easy,let`s go!

二. 功能函數(shù)實現(xiàn)
手摸手第二步。在第二步我們先把#1、#2、#3三個功能函數(shù)實現(xiàn)一下。

首先是#1函數(shù)isHidden的實現(xiàn)。

/**
 * 判斷目標(biāo)元素是否可見
 * https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/offsetParent
 * @param {HTMLElement} element
 * @returns {boolean}
 */
var isHidden = function (element) {
    return element.offsetParent === null;
};

接下來是#2函數(shù)canLoadImg的實現(xiàn)。這兒用到了Element.getBoundingClientRect()方法返回元素的大小及其相對于視口的位置。關(guān)于Element.getBoundingClientRect()的信息請點擊傳送陣了解更多。

/**
 * 判斷目標(biāo)元素是否進入懶加載區(qū)域
 * 此函數(shù)依賴isHidden函數(shù)和boxRect全局變量
 * @param {HTMLElement} element
 * @returns {boolean}
 */
var canLoadImg = function (element) {
    if (isHidden(element)) return false;
    var eleRect = element.getBoundingClientRect();
    return (eleRect.top <= boxRect.b && eleRect.right >= boxRect.l && eleRect.bottom >= boxRect.t && eleRect.left <= boxRect.r);
};

最后是#3函數(shù)onDebounceRender的實現(xiàn)。由于這里對節(jié)流函數(shù)沒什么特殊需求,所以實現(xiàn)的比較簡單,如果看官同學(xué)需要完整的debounce函數(shù),請點擊lodash/debounce.js了解更多。

/**
 * 節(jié)流函數(shù)
 * 此函數(shù)依賴Lazy.render、debounce、timer、delay
 */
var onDebounceRender = function () {
    if (!debounce) {
        Lazy.render();
    } else {
        clearTimeout(timer);
        timer = setTimeout(function () {
            Lazy.render();
            timer = null;
        }, delay);
    }
};
三. 初始化函數(shù)
手摸手第三步。我們來實現(xiàn)一下Lazy.init初始化函數(shù)。這個函數(shù)的作用就是接收參數(shù)、綁定事件處理函數(shù),所以更簡單。
/**
 * 始化方法,外部直接調(diào)用,配置參數(shù)在此接收
 * @param {Object} options
 * @param {String} options.root - 圖片滾動區(qū)域根元素選擇器
 * @param {Number} options.offset - 懶加載閾值,當(dāng)沒有上下左右有4個值時將以此為準(zhǔn)
 * @param {Number} options.offsetTop - 懶加載閾值【上】
 * @param {Number} options.offsetRight - 懶加載閾值【右】
 * @param {Number} options.offsetBottom - 懶加載閾值【下】
 * @param {Number} options.offsetLeft - 懶加載閾值【左】
 * @param {Boolean} options.debounce - 是否開啟函數(shù)節(jié)流
 * @param {Number} options.delay - 函數(shù)節(jié)流時間閾值
 * @param {Boolean} options.unload - 圖片重載
 * @param {Function} options.callback - 懶加載操作完成時的回掉函數(shù)
 */
Lazy.init = function (options) {
    options = options || {};
    global = document.querySelector(options.root) || global;
    debounce = options.debounce !== false;
    delay = options.delay || delay;
    unload = options.unload || unload;
    callback = options.callback || callback;
    // 懶加載區(qū)域,寫的雖然有點長但是不難理解
    boxRect = {
        t: 0 - (options.offsetTop || options.offset || 0),
        r: (global.innerWidth || document.documentElement.clientWidth) + (options.offsetRight || options.offset || 0),
        b: (global.innerHeight || document.documentElement.clientHeight) + (options.offsetBottom || options.offset || 0),
        l: 0 - (options.offsetLeft || options.offset || 0)
    };
    // 這里提前調(diào)用一次,因為如果debounce為true,load之后會有最低250ms的延遲
    Lazy.render();
    // 綁定事件
    if (global.addEventListener) {
        global.addEventListener("load", onDebounceRender, false);
        global.addEventListener("scroll", onDebounceRender, false);
    } else {
        global.attachEvent("onload", onDebounceRender);
        global.attachEvent("onscroll", onDebounceRender);
    }
};
四. 核心方法實現(xiàn)
手摸手第四步。在第四步我們來完成Lazy.render函數(shù)的實現(xiàn)。這個函數(shù)也是本項目的核心方法,所有的懶加載實現(xiàn)都是在此處完成。思路不復(fù)雜,所以實現(xiàn)起來也比較簡單。
/**
 * 懶加載實現(xiàn)
 * @param {HTMLElement} element
 */
Lazy.render = function (element) {
    // dom結(jié)構(gòu)約定:img標(biāo)簽要有[data-lazy]自定義屬性,需要設(shè)置背景的標(biāo)簽需要有[data-lazy-background]自定義屬性
    var nodes = (element || document).querySelectorAll("[data-lazy], [data-lazy-background]");
    var len = nodes.length;
    for (var i = 0; i < len; i++) {
        var node = nodes[i];
        // 目標(biāo)元素在懶加載區(qū)域和不在懶加載區(qū)域
        if (canLoadImg(node)) {
            // 懶加載圖片需要重載,懶加載之前先將占位圖片存儲
            if (unload && node.src && !node.getAttribute("data-lazy-placeholder")) {
                node.setAttribute("data-lazy-placeholder", node.src);
            }
            // 圖片的懶加載
            var src = node.getAttribute("data-lazy");
            if (src !== null && node.src !== src) {
                node.src = src;
            }
            // 背景的懶加載
            var bgUrl = node.getAttribute("data-lazy-background");
            if (bgUrl !== null && node.style.backgroundImage !== bgUrl) {
                node.style.backgroundImage = "url(" + bgUrl + ")";
            }
            // 如果圖片不需要重載,懶加載完成移除[data-lazy]自定義屬性
            if (!unload) {
                node.removeAttribute("data-lazy");
            }
            // 懶加載完成移除[data-lazy-background]自定義屬性
            node.removeAttribute("data-lazy-background");
            // 懶加載完成觸發(fā)回掉
            callback(node, "load");
        } else {
            // 當(dāng)圖片不在懶加載區(qū)域時做重載處理
            var placeholder = node.getAttribute("data-lazy-placeholder");
            if (unload && placeholder !== null) {
                node.src = placeholder;
                // 移除[data-lazy-placeholder]自定義屬性
                node.removeAttribute("data-lazy-placeholder");
                // 重載完成觸發(fā)回掉
                callback(node, "unload");
            }
        }
    }
    // 如果沒有懶加載的元素,銷毀Lazy.init添加的事件
    if (len === 0) {
        Lazy.destroy();
    }
};
五. 解綁方法實現(xiàn)
手摸手第五步。這一步更簡單,話不多說直接看代碼。
/**
 * 不滿足懶加載條件時移除綁定的事件,重置定時器引用
 */
Lazy.destroy = function () {
    if (document.removeEventListener) {
        global.removeEventListener("scroll", onDebounceRender);
    } else {
        global.detachEvent("onscroll", onDebounceRender);
    }
    clearTimeout(timer);
};
六. 結(jié)語

由于景科同學(xué)剛開始寫博文,語文老師走的又早(是真的早)?,文筆難免摳腳,不足之處還望各位看官同學(xué)多多包含。本項目是景科同學(xué)自寫自測,雖然比較簡單,但是不保證沒有隱藏的bug。所以如果看官同學(xué)發(fā)現(xiàn)還望留言指正,景科同學(xué)在此以示感謝。

本文完整代碼請點這里。

如果大神同學(xué)看到此處,更希望你能留下批評指正的意見,這樣景科同學(xué)才能更快的進步,下次如果你們不小心點開景科同學(xué)寫的文章才不會白花花的浪費寶貴的時間,誰說不是呢?!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/94064.html

相關(guān)文章

  • 摸手,帶你封裝一個vue component

    摘要:靈活性和針對性。所以我覺得大部分組件還是自己封裝來的更為方便和靈活一些。動手開干接下來我們一起手摸手教改造包裝一個插件,只要幾分鐘就可以封裝一個專屬于你的。 項目地址:vue-countTo配套完整后臺demo地址:vue-element-admin系類文章一:手摸手,帶你用vue擼后臺 系列一(基礎(chǔ)篇)系類文章二:手摸手,帶你用vue擼后臺 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶...

    pkhope 評論0 收藏0
  • 摸手,帶你用vue擼后臺 系列三(實戰(zhàn)篇)

    摘要:社區(qū)的認(rèn)可目前已經(jīng)是相關(guān)最多的開源項目了,體現(xiàn)出了社區(qū)對其的認(rèn)可。監(jiān)聽事件手動維護列表這樣我們就簡單的完成了拖拽排序。 完整項目地址:vue-element-admin 系類文章一:手摸手,帶你用vue擼后臺 系列一(基礎(chǔ)篇)系類文章二:手摸手,帶你用vue擼后臺 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶你用vue擼后臺 系列三(實戰(zhàn)篇)系類文章四:手摸手,帶你用vue擼后臺 系列...

    Channe 評論0 收藏0
  • 摸手,帶你用vue擼后臺 系列三(實戰(zhàn)篇)

    摘要:社區(qū)的認(rèn)可目前已經(jīng)是相關(guān)最多的開源項目了,體現(xiàn)出了社區(qū)對其的認(rèn)可。監(jiān)聽事件手動維護列表這樣我們就簡單的完成了拖拽排序。 完整項目地址:vue-element-admin 系類文章一:手摸手,帶你用vue擼后臺 系列一(基礎(chǔ)篇)系類文章二:手摸手,帶你用vue擼后臺 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶你用vue擼后臺 系列三(實戰(zhàn)篇)系類文章四:手摸手,帶你用vue擼后臺 系列...

    zgbgx 評論0 收藏0
  • 摸手,帶你用vue擼后臺 系列一(基礎(chǔ)篇)

    摘要:詳細具體的使用可以見文章手摸手,帶你優(yōu)雅的使用。為了加速線上鏡像構(gòu)建的速度,我們利用源進行加速并且將一些常見的依賴打入了基礎(chǔ)鏡像,避免每次都需要重新下載。 完整項目地址:vue-element-admin系類文章二:手摸手,帶你用vue擼后臺 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶你用vue擼后臺 系列三(實戰(zhàn)篇)系類文章四:手摸手,帶你用vue擼后臺 系列四(vueAdmin 一...

    xiaotianyi 評論0 收藏0
  • 摸手,帶你用vue擼后臺 系列五(v4.0新版本)

    摘要:同時增加了單元測試,使用了,增加了可視化配置權(quán)限,增加了自定義布局等等,優(yōu)化了原先的權(quán)限方案,支持不刷新頁面更新路由等等功能。雖然它的初衷是為了單元測試的,但正好滿足了我們的需求。它會重寫瀏覽器的對象,從而才能攔截所有請求,代理到本地。 前言 vue-element-admin 從 2017.04.17提交第一個 commit 以來,維護至今已經(jīng)有兩年多的時間了了,發(fā)布了四十多個版本,...

    MonoLog 評論0 收藏0

發(fā)表評論

0條評論

CompileYouth

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<