vue實現瀑布流

一開始以爲這個問題很簡單,每插入一張圖片以前比較各個「流」的高度,找個最短的放進去就好了。後來發現沒那麼簡單。 直接想到的問題就是圖片未加載完成是得不到圖片的完整高度的,後來找到dom的naturalHeight屬性,能夠在圖片未加載成功時就獲取到圖片高度html

而後開始常規操做,用nextTick遞歸把圖片數據插入到對應的數組中,可是nextTick中獲取圖片dom的naturalHeight是獲取不到的,可是頁面中圖片就算未加載完成是能夠獲取到的。猜測是vue渲染完圖片的dom時執行nextTick,圖片剛開始加載,這時候接口尚未獲取到計算naturalHeight屬性相關的數據。因此這條路就是走死了,由於這個方法下圖片何時加載完成沒法監控,都是第一張圖片插入以後第二張圖片放哪裏無法計算。vue

第一時間想到的就是setInterval,而後不到一秒鐘就被本身否決了,醜並且耗費性能,寧願在數據庫裏擴展width、height字段也不用這個方法(我還真的擴展了)。可是不太服氣,而後尋找盡是廣告的度娘,發現一個方法,既然以前問題出在圖片何時加載完成沒法監控,那就用image.onload()方法獲取圖片信息,而後在回調裏面丁零當啷一頓操做拼好dom,插入到頁面中。 偷來的代碼數據庫

sort(j) {
    if (j < this.moments.length) {
        let that = this;
        // 建立Image類
        var newImg = new Image();
        // 獲取要加載的圖片地址
        newImg.src =
            "http://lanyue.ink:8123/images/" +
            (Math.floor(Math.random() * 15) + 1) +
            ".png";
        // 圖片加載完成後(異步)
        newImg.onload = () => {
            // 四個管道的高度 
            var arr = [
                that.$refs.piping0.offsetHeight,
                that.$refs.piping1.offsetHeight,
                that.$refs.piping2.offsetHeight,
                that.$refs.piping3.offsetHeight
            ];
            //獲取管道最小高度
            var min = arr.indexOf(Math.min.apply(Math, arr));
            // 添加卡片的模板
            var html =
                `<div class="card">
                    <img src=` + newImg.src + `>
                        <div>
                            <img src="http://lanyue.ink:8123/images/avatar.jpg" alt="">
                            <div>` + this.moments[j].id + " " + this.moments[j].content + `</div>
                        </div>
                    </div>`;
            //給最小的管道添加卡片
            if (min == 0) {
                that.$refs.piping0.innerHTML += html;
            } else if (min == 1) {
                that.$refs.piping1.innerHTML += html;
            } else if (min == 2) {
                that.$refs.piping2.innerHTML += html;
            } else if (min == 3) {
                that.$refs.piping3.innerHTML += html;
            }
            that.sort(j + 1);
        };
    }
},
複製代碼

做者若是看到了不要噴我,都走到這一步了,爲何還要用插入html的方式,拿到圖片的寬高,加一個計算「流」高度的字段,插入一張圖就加一個圖片的高度,這樣也就不用再從dom中獲取「流」的高度。這樣的好處有兩個,一是減小一次dom的查詢,二是若是頁面須要響應式,插入html的方式實際上是沒法經過直接改變數據操做dom,違背了vue的本意(對於兩個方法的性能消耗有機會多作研究,感受起來應該是個人方法美一點)。數組

getImageList() {
    let that = this;
    imageService.getImageList(this, {
        params: {
            categoryId: 37
        }
    }).then(function (result) {
        if (result.code === 0) {
            that.tempImage = result.data;
            that.pushImage(0);
        }
    });
},

pushImage(index) {
    if (index >= this.tempImage.length) return;
    let img = new Image(), that = this;
    img.src = that.$store.state.imageURL + that.tempImage[index].url;
    img.onload = () => {
        let min = that.imageHeight[0], imageIndex = 0;
        that.imageHeight.forEach(function (item, _index) {
            if (min > item) {
                min = item;
                imageIndex = _index;
            }
        });
        that.imageHeight[imageIndex] += img.naturalHeight / img.naturalWidth;
        that.imageList[imageIndex].push(that.tempImage[index]);
        that.pushImage(index + 1);
    }
},
複製代碼

最後再加上一段監控頁面位置函數,實現拉到底部加載圖片的功能bash

pullDown() {
    // 獲取滾輪位置
    this.height1 = window.pageYOffset ||
        document.documentElement.scrollTop ||
        document.body.scrollTop;
    // 文檔高度
    this.height2 = document.body.scrollHeight;
    // 可視區域
    // 設置compatMode兼容IE
    this.height3 = document.compatMode === "CSS1Compat"
        ? document.documentElement.clientHeight
        : document.body.clientHeight;
    // 若是滾動到最低(這裏設置離最底還有100距離才觸發函數)
    // available條件是爲了防止觸底時一直不斷地請求。所以,請求一次後available設爲0,直到滾動到離底部超過100距離(即數據加載玩後)才設爲1
    if (this.height3 + this.height1 >= this.height2 - 100 && this.available) {
        this.available = false;
        //請求下一頁,若是當前頁等於最大頁,直接返回
        if (this.pagination.currentPage >= this.pagination.totalPage) {
            this.footerVisible = true;
            return;
        }
        this.pagination.currentPage++;
        this.getImagePage();
    } else if (this.height3 + this.height1 < this.height2 - 100) {
        this.available = true;
    }
}

複製代碼

最終效果圖 app

參考文章:來自MarieDreamer blog.csdn.net/qq_33514421…dom

相關文章
相關標籤/搜索