uniapp小程序實現瀑佈流佈局的思路與代碼

一、前言

現在寫瀑佈流算不算是炒冷飯啊?

我不管, 我就要寫,誰也別想攔我。

瀑佈流應該算是很常見的一種佈局方法瞭,大致的思路也很好理解, 但是在小程序裡面確有另外需要考慮的幾個問題。

問題1:uniapp是基於Vue的,所以不好直接操作DOM。

問題2:uniapp基於Vue,但也做瞭一些修改,所以不好拿ref來操作

二、先說思路

為瞭保證文章的長度,以及有些小夥伴對瀑佈流的基本思路不是很瞭解,所以先講講瀑佈流的思路,先看下圖。

可以看到,商品的圖片高度是不一致的,再加上商品標題的行數不一致,最終呈現的效果是交錯排列的。

之前在開發過程中,我也試過用CSS的Flex佈局,Column佈局來實現,勉強能實現同樣的效果,但是最終對接後臺要考慮商品的熱度優先,所以隻能放棄。

Flex實現缺點:使用Flex佈局並不能準確計算高度來插入商品。

Column實現缺點:使用Column佈局不好操作先後順序。

PS:如果對產品排序沒有要求的話, 可以考慮純CSS實現,這裡不多贅述,掘金裡很多的。

三、核心代碼

如題,本文對於瀑佈流的實現是基於uniapp開發小程序的,如果期望JS原生實現,本文的很多思路是需要修改的。
先解答部分疑惑:

因為無法通過$refs獲取到列的高度,所以代碼是通過Image標簽的@load時間先加載一次圖片,並將圖片的寬高等信息傳遞給方法。

// component/waterfall.vue
<template>
    <view class="waterfall">
        <view hidden>
            // 用JS原生實現時可以直接用for循環插入,然後獲取列高度
            // 這裡通過載入圖片調用方法, 默認傳參帶有圖片信息,可以獲得圖片高度
            <block v-for(item in imgList" :key="item.id">
                <image :src="item.url" @load="loadImg" ></iamge>
            </block>
        </view>
        <view class="list" v-for="(list, key) in waterfall" :key="key">
            <navigator url="https://www.baidu.com" v-for="item in list.list" :key="item.id">
                <image :src="item.url" mode="widthFix"></image>
                <view class="shop-info">
                    /* 標題等信息,略 */
                </view>
            </navigator>
        </view>
    </view>
</template>

<script>
    export default {
        // 抽出為單獨的組件,所以數據來源於父組件傳遞,也可以是當前組件請求API
        props: { imgList: Array },
        data(){
            return {
                lists: [], // 備份imgList用的數組,方便操作
                waterfall: [
                    // 用於記錄當前列的高度,不在方法中保存是為瞭上拉獲取新數據也能使用
                    // 因為默認手機顯示,可以固定兩列
                    // 如果是做自適應或者電腦端多列,可以動態插入實現多列
                    {
                        height: 0, 
                        list: []
                    },{
                        height: 0, 
                        list: []
                    }
                ]
            }
        },
        created(){
            this.lists = this.imgList; // Vue創建data後立即備份
        },
        watch(){
            // 監聽數據源,如果有新值傳入,則用lists數組備份
            imgList(data){ data.length && this.lists.push(...data); }
        },
        methods: {
            loadImg(ev){
                let Root = this.waterfall;
                let height = e.detail.height;
                // 根據當前高度決定將新數據給誰,並更新列高度;優先插入左側
                if(Root[0].height <= Root[1].height){
                    // 考慮熱度優先的問題, 所以用的是shift()方法推出頭部數據。
                    Root[0].list.push(this.lists.shift())
                    Root[0].height += height;
                } else {
                    Root[1].list.push(this.lists.shift())
                    Root[1].height += height;
                }
            }
        }
    }
</script>

至此,核心代碼就完成瞭。

PS:因為要借由image的@load事件來觸發方法,所以大量加載勢必會影響性能,所以要自己做點取舍瞭。

四、總結

希望如果有小夥伴看完這篇文章之後,決定使用這個方法時,能記得一件事,這個寫法可能有性能問題方面的影響,能在這方面下功夫去深入研究下。

到此這篇關於uniapp小程序實現瀑佈流佈局的思路與代碼的文章就介紹到這瞭,更多相關uniapp小程序瀑佈流佈局內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!