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

資訊專欄INFORMATION COLUMN

原生 js 實(shí)現(xiàn)面對(duì)對(duì)象版瀑布流

tommego / 2322人閱讀

摘要:一一些閑話作為一個(gè)寫靜態(tài)的切圖仔,其實(shí)日常工作中根本用不上瀑布流這種小清新,畢竟?fàn)I銷頁(yè)面都是要求搶眼吸睛高大上文案爸爸說(shuō)啥都對(duì)。昨上午閑著沒(méi)事看到別人寫的瀑布流的帖子,覺(jué)得很好玩的樣子,然后決定上午就寫一個(gè)試試。。。

一、一些閑話

作為一個(gè)寫靜態(tài)的切圖仔,其實(shí)日常工作中根本用不上瀑布流這種小清新,畢竟?fàn)I銷頁(yè)面都是要求 搶眼__、__吸睛__、 __高大上 (文案爸爸說(shuō)啥都對(duì))。

昨上午閑著沒(méi)事看到別人寫的瀑布流的帖子,覺(jué)得很好玩的樣子,然后決定上午就寫一個(gè)試試。。。所以,今天下午,就來(lái)整理下這過(guò)程中的一些思路。

二、需求整理及最終效果

寫代碼之前大概列了一下需求,然后中間又加上了一些其他功能,最終的需求如下:

2.1 需求列表

1、希望是用原生 js 代碼,jq 寫多了怕忘了原生;

2、面對(duì)對(duì)象方式封裝,根據(jù)圖片數(shù)據(jù)渲染頁(yè)面;

3、瀑布流部分可以添加至任意容器元素內(nèi),畢竟頁(yè)面還會(huì)有其他內(nèi)容;

4、圖片寬度,行列間距可定義;

5、圖片外容器可以自定義邊框、陰影等屬性;

6、圖片數(shù)據(jù)增加后可以調(diào)用方法渲染新增部分,原始部分保存不變;

2.2 最終效果

完整代碼
頁(yè)面預(yù)覽

3秒后新增3張圖片

三、代碼實(shí)現(xiàn) 3.1 基礎(chǔ)框架
起一個(gè)自執(zhí)行函數(shù),只需要暴露一個(gè) falls 變量,該變量指向一個(gè)包含 init 方法的對(duì)象;
init 方法有2個(gè)參數(shù):
- el:瀑布流的容器的選擇符
- options:其他參數(shù)

ps: 這里還用到了一個(gè)自定義的 extend 方法,用于合并默認(rèn)屬性以及自定義屬性對(duì)象,怕被說(shuō)兼容性不好就沒(méi)有用 ES6 語(yǔ)法,參照 Object.assign 方法,完整代碼里也有,此處不多介紹;

var falls = (function () {
    var defaults = {

    };

    var Falls = function (el, options) {

    };

    var prototype = Falls.prototype;

    var init = function (el, options) {
        options = extend([], defaults, options);
        return new Falls(el, options).init();
    };

    return {
        init: init
    }
})();
3.2 基礎(chǔ)屬性
接下來(lái)確定一些可以定義的屬性:
- width: 圖片(圖片外容器)的寬度
- colSpace: 列間距
- rowSpace: 行間距
- itemClass: 圖片外容器類名,方便修改邊框、陰影等樣式

根據(jù)這些屬性,隨手確定了各項(xiàng)默認(rèn)值

var defaults = {
    width: 220,
    colSpace: 10,
    rowSpace: 10,
    itemClass: "_list-item"
};
3.3 構(gòu)造函數(shù)
定義 Falls 構(gòu)造函數(shù),最終該構(gòu)造函數(shù)有以下初始屬性(屬性在后面用到再做解釋):
var Falls = function (el, options) {
    this.el = document.querySelector(el);
    this.imgList = options.imgList;
    this.colSpace = options.colSpace;
    this.rowSpace = options.rowSpace;
    this.width = options.width;
    this.itemClass = options.itemClass;
    this.first = true;
    this.startIndex = 0;
    this.callback = [];
    this.loadAll = false;
};
3.4 添加原型方法
在添加原型方法之前:
var prototype = Falls.prototype;

這樣可以少寫好多字母呢,真棒?。?!

3.4.1 初始化 initialize 方法
prototype.initialize = function () {
    var rootEl = document.createElement("div");

    rootEl.style.margin = "0 auto";
    rootEl.style.position = "relative";

    this.rootEl = rootEl;
    this.el.appendChild(this.rootEl);
};

這里定義了根元素 rootEl ,并給它添加了相對(duì)定位及 margin 屬性,這樣整個(gè)根元素會(huì)在容器中水平居中。

3.4.2 瀑布流加載 loadFalls 方法
這里有一些前置屬性及初始邏輯
prototype.loadFalls = function () {
    var wrapWidth = this.el.clientWidth;    // 獲取容器的寬度
    this.colWidth = this.width + this.colSpace;     // 單個(gè)圖片加上列間隙需要的寬度
    this.col = Math.floor((wrapWidth + this.colSpace) / this.colWidth); // 獲取圖片列數(shù)
    this.rootEl.style.width = this.col * this.colWidth - this.colSpace + "px";  // 根元素的寬度

    if (this.first) {   // 如果初次渲染,直接執(zhí)行
        this.storageTop();
        this.addItem();
        this.first = false;
        this.lastCol = this.col;
    } else {    // 非初次渲染,判斷列數(shù)是否變化
        if (this.lastCol !== this.col) {
            this.startIndex = 0;    // 列數(shù)變化時(shí),全部重新渲染
            this.rootEl.innerHTML = "";     // 清空根元素
            this.storageTop();
            this.addItem();
            this.lastCol = this.col;
        }
    }
};

以代碼空行來(lái)拆分:

第一部分:__屬性定義__,見(jiàn)注釋。

第二部分:__邏輯部分__

如果是第一次渲染,就依次初始化,執(zhí)行 addItem 添加圖片列表,然后標(biāo)記 this.first 為 false,并且記錄當(dāng)前的列數(shù) this.lastCol

非第一次渲染,只有列數(shù)改變時(shí)才重新渲染瀑布流,this.startIndex 是圖片數(shù)組的標(biāo)記位,后面會(huì)講到。

3.4.3 生成高度列表 storageHeight 方法
prototype.storageTop = function () {
    var topArr = [];
    for (var i = 0; i < this.col; i++) {
        topArr.push({
            left: this.colWidth * i,
            top: 0
        })
    }
    this.topArr = topArr;
};

根據(jù)列數(shù)生成一個(gè)存儲(chǔ)每列下一張圖片 top 及 left 值的數(shù)組,top 初始都為 0 ,left 為每列的寬度 * 列數(shù);

3.4.4 添加圖片隊(duì)列 addItem 方法
prototype.addItem = function () {
    var _this = this,
        maxHeight = 0,
        topArr = this.topArr,
        imgList = this.imgList.slice(_this.startIndex),
        len = topArr.length;

    (function addImg() {
        var current = imgList.shift(),
            top = topArr[0].top,
            index = 0;
        for (var j = 1; j < len; j++) { // 遍歷求出當(dāng)前最小 top 值,及對(duì)應(yīng)的列數(shù) index
            if (topArr[j].top < top) {
                top = topArr[j].top;
                index = j;
            }
        }

        var item = document.createElement("div");   // 創(chuàng)建圖片包裹元素
        item.style.position = "absolute";
        item.style.top = top + "px";
        item.style.left = topArr[index].left + "px";
        item.style.width = _this.width + "px";
        item.style.boxSizing = "border-box";
        item.classList.add(_this.itemClass);

        var img = document.createElement("img");    // 創(chuàng)建圖片元素
        img.style.width = "100%";
        img.src = current.src;
        img.alt = current.alt;

        item.appendChild(img);
        _this.rootEl.appendChild(item);

        img.onload = function () {
            topArr[index].top += item.offsetHeight + _this.rowSpace;  // 新增圖片后更新高度數(shù)組
            maxHeight = maxHeight < topArr[index].top ? topArr[index].top : maxHeight;
            _this.rootEl.style.height = maxHeight + "px";   // 更新容器的高度

            if (imgList.length) {
                addImg();
            } else {
                _this.startIndex = _this.imgList.length;
                if (!_this.callback.length) {
                    _this.loadAll = true;
                } else {
                    _this.callback.shift()();
                }
            }
        };
    })();
};

這一塊有點(diǎn)長(zhǎng),因?yàn)橛袃商帪?dom 對(duì)象添加屬性,主要邏輯如下:

1、變量聲明,保存 this ,復(fù)制圖片數(shù)組至 imgList(因?yàn)楹竺鏁?huì)對(duì)數(shù)組進(jìn)行更改);

2、創(chuàng)建 addImg 方法添加單個(gè)圖片進(jìn)根元素,在圖片的 onload 事件里遞歸 addImg 添加下一張圖片;

只有在圖片加載完成后才能獲取圖片高度,進(jìn)行 topArr 的更新

3、在 addImg 函數(shù)內(nèi),首先遍歷出當(dāng)前最小 top 值,及對(duì)應(yīng)的列數(shù) index;

4、生成圖片容器元素 item ,并添加屬性及暴露的類名 itemClass;

5、生成圖片元素 img ,并添加屬性,圖片寬度100%;

6、依次添加圖片及圖片容器至根元素,注意先后順序;

7、進(jìn)入 onload 事件內(nèi),首先需要更新 topArr 對(duì)應(yīng)序號(hào)的 top 值,因?yàn)樵撐恢眯略隽艘粡垐D片

8、求出總高度更新根元素高度(防止根元素后面其他頁(yè)面元素布局混亂);

9、如果 imgList 內(nèi)還有數(shù)據(jù),遞歸完成圖片添加

10、如果 imgList 無(wú)數(shù)據(jù):

記錄圖片索引至 startIndex ,新增圖片數(shù)據(jù)后只需從 startIndex 位置開(kāi)始添加

檢查回調(diào)隊(duì)列 callback 內(nèi)是否有回調(diào)事件,如果有,取出第一條進(jìn)行處理(回調(diào)隊(duì)列后面解釋)

3.4.5 監(jiān)聽(tīng)寬度變化 bindEvent 方法
prototype.bindEvent = function () {     // 通過(guò) resize 事件監(jiān)聽(tīng)容器寬度變化
    window.addEventListener("resize", this.loadFalls.bind(this));
};

為 window 對(duì)象的 resize 事件添加監(jiān)聽(tīng),觸發(fā) loadFalls 函數(shù),這里通過(guò)bind修正了方法內(nèi)部的 this 指向;

3.4.6 生成一個(gè)瀑布流實(shí)例 init 方法
prototype.init = function () {  //  生成一個(gè)瀑布流實(shí)例
    this.initialize();
    this.loadFalls();
    this.bindEvent();
    return this;    // 返回實(shí)例對(duì)象
};

就是依次調(diào)用 初始化 添加圖片 綁定事件 三個(gè)方法,這里返回了 this ,用于保存當(dāng)前實(shí)例,下一步會(huì)用到;

3.4.7 添加圖片后重新繪制 addImgReload 方法
prototype.addImgReload = function (arr) {
    var _this = this;
    if (this.loadAll) {
        this.imgList = arr;
        this.addItem();
    } else {
        this.callback.push(function () {
            _this.imgList = arr;
            _this.addItem();
        })
    }
};

上面為了這一步做了很多鋪墊

this.loadAll 保存當(dāng)前圖片隊(duì)列是否全部加載完成

如果當(dāng)前圖片隊(duì)列已經(jīng)加載完成,那就跟新圖片隊(duì)列 this.imgList ,繼續(xù)加載 this.addItem(),因?yàn)橐呀?jīng)存儲(chǔ)了 startIndex ,所以會(huì)從新增的圖片繼續(xù)加載

如果當(dāng)前圖片隊(duì)列還沒(méi)加載完成,將更新圖片的任務(wù)推進(jìn)回調(diào)隊(duì)列 callback ,當(dāng)前圖片隊(duì)列加載完成后會(huì)檢測(cè)回調(diào)隊(duì)列,取出更新圖片任務(wù)完成,就算有多個(gè)圖片更新事件也不要緊, callback 保持先進(jìn)先出執(zhí)行順序;

四、總結(jié)

似乎沒(méi)有提懶加載

通過(guò) addImgReload 方法分次跟新圖片屬性可以實(shí)現(xiàn)懶加載

圖片數(shù)據(jù)可以根據(jù)實(shí)際擴(kuò)充,此處只添加了 src 及 alt ,包括超鏈接可以修改外層容器 item 或者再套一層;

代碼寫完沒(méi)有做優(yōu)化,有幾段比較長(zhǎng),有空再優(yōu)化吧,畢竟快下班了

最后,個(gè)人能力有限,歡迎大佬補(bǔ)充,謝謝?。。?/p>

編輯文章的時(shí)候發(fā)現(xiàn)了一個(gè)坑,圖片加載失敗會(huì)阻塞后續(xù)圖片,明天改

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

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

相關(guān)文章

  • 原生js實(shí)現(xiàn)瀑布及微信小程序中使用左右兩列實(shí)現(xiàn)瀑布

    摘要:使用實(shí)現(xiàn)瀑布流并不實(shí)用,因?yàn)閷?shí)現(xiàn)的瀑布流都是以列來(lái)排列的,這里記錄下用實(shí)現(xiàn)瀑布流,以及微信小程序中使用左右兩列來(lái)實(shí)現(xiàn)瀑布流效果圖原生實(shí)現(xiàn)瀑布流文件圖片可以自己找點(diǎn)替換下就可以了文件添加陰影的時(shí)候,加上會(huì)顯得更加有點(diǎn)懸浮感文件計(jì)算圖片列數(shù) 使用css實(shí)現(xiàn)瀑布流并不實(shí)用,因?yàn)閏ss實(shí)現(xiàn)的瀑布流都是以列來(lái)排列的,這里記錄下用js實(shí)現(xiàn)瀑布流,以及微信小程序中使用左右兩列來(lái)實(shí)現(xiàn)瀑布流 1.效果圖...

    imingyu 評(píng)論0 收藏0
  • 原生js實(shí)現(xiàn)瀑布效果

    摘要:前言最近在整理基礎(chǔ)知識(shí),接觸到了幾個(gè)常用的頁(yè)面特效,其中覺(jué)得用原生實(shí)現(xiàn)瀑布流的案例十分有趣,于是與大家分享一下。瀑布流瀑布流,又稱瀑布流式布局。通過(guò)定位的方式是我們實(shí)現(xiàn)瀑布流的最基本的原理,只要我們動(dòng)態(tài)的設(shè)置它的值值,就能讓它排列。 showImg(https://segmentfault.com/img/remote/1460000012621941?w=1052&h=542); 前...

    wangdai 評(píng)論0 收藏0
  • 原生 JS 實(shí)現(xiàn)一個(gè)瀑布插件

    摘要:瀑布流布局中的圖片有一個(gè)核心特點(diǎn)等寬不定等高,瀑布流布局在國(guó)內(nèi)網(wǎng)網(wǎng)站都有一定規(guī)模的使用,比如花瓣網(wǎng)等等。那么接下來(lái)就基于這個(gè)特點(diǎn)開(kāi)始瀑布流探索之旅。 showImg(https://segmentfault.com/img/remote/1460000013059759?w=640&h=280); 瀑布流布局中的圖片有一個(gè)核心特點(diǎn) —— 等寬不定等高,瀑布流布局在國(guó)內(nèi)網(wǎng)網(wǎng)站都有一定規(guī)模...

    Alfred 評(píng)論0 收藏0
  • 原生 JS 實(shí)現(xiàn)一個(gè)瀑布插件

    摘要:瀑布流布局中的圖片有一個(gè)核心特點(diǎn)等寬不定等高,瀑布流布局在國(guó)內(nèi)網(wǎng)網(wǎng)站都有一定規(guī)模的使用,比如花瓣網(wǎng)等等。那么接下來(lái)就基于這個(gè)特點(diǎn)開(kāi)始瀑布流探索之旅。 showImg(https://segmentfault.com/img/remote/1460000013059759?w=640&h=280); 瀑布流布局中的圖片有一個(gè)核心特點(diǎn) —— 等寬不定等高,瀑布流布局在國(guó)內(nèi)網(wǎng)網(wǎng)站都有一定規(guī)模...

    lavnFan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

tommego

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<