Skip to content

瀑布流

一、网格布局 display: grid

关键代码:

vue
<view class="item" :key="index" :style="'grid-row: auto / span '+ (arrRowList[index] || 0) +';'">
</view>
vue
//获取元素高度
let height = ret.height;
//计算span
span = Math.floor(height / 5) + 2;

关键样式:

css
.list{
    display: grid;
    /*指定两列,自动宽度*/
    grid-template-columns: repeat(2, 1fr);
    /*横向间隔*/
    grid-column-gap: 24rpx;
    grid-row-gap: 0;
    /*是否自动补齐空白*/
    grid-auto-flow: row dense;
    /*base高度,grid-row基于此运算*/
    grid-auto-rows: 5px;  
}

完整代码:

vue
<template>
    <view class="flow-wrap">
        <List ref="list" :openLoad="!bAllLoaded" @refresh="loadTop" @load="loadBottom">
            <view class="list">
                <template v-for="(item,index) in arrList">
                    <view class="item" :key="index"
                          :style="'grid-row: auto / span '+ (arrRowList[index] || 0) +';'">
                        <image :src="item.url" class="img" mode="widthFix"></image>
                        <view class="text">{{ item.text }}({{index + 1}})</view>
                    </view>
                </template>
            </view>
        </List>
        <view id="count" class="count-box">
            <view class="item">
                <image :src="objItem.url" class="img" mode="widthFix"></image>
                <view class="text">{{ objItem.text }}</view>
            </view>
        </view>
    </view>
</template>

<script>
import List from '/src/components/list/list';

export default {
    name: "flow",
    components: {
        List
    },
    data() {
        return {
            bAllLoaded: false,
            objItem: {},//用于计算高度的数据
            arrList: [],
            arrRowList: []
        }
    },
    methods: {
        upDate() {
            uni.showLoading({
                title: '加载中',
                mask: true
            })
            this.arrRowList = [];
            this.arrList = [];
            this.getList().then(() => {
                uni.hideLoading()
            })
        },
        itemStyle(index) {
            const item = this.imageList[index]
            const itemWidth = (this.screenWidth - (this.columnNum - 1) * this.columnGap) / this.columnNum
            const itemHeight = item.height * (itemWidth / item.width)
            const colIndex = index % this.columnNum
            const rowIndex = Math.floor(index / this.columnNum)
            const marginTop = rowIndex === 0 ? 0 : this.columnGap
            const marginLeft = colIndex === 0 ? 0 : this.columnGap
            return {
                width: `${itemWidth}px`,
                height: `${itemHeight}px`,
                marginTop: `${marginTop}px`,
                marginLeft: `${marginLeft}px`,
            }
        },
        getList() {
            return new Promise((resolve, reject) => {
                // 模拟接口返回
                setTimeout(() => {
                    let arr = [{
                        url: 'https://pro-mixed-test.babycdn.com/base/digi/uploads/digi_demo/46/43/1679624643_5266.jpg',
                        text: '文本'
                    }, {
                        url: require('@/static/image/flow/flow2.jpg'),
                        text: '文本'
                    }, {
                        url: require('@/static/image/flow/flow2.jpg'),
                        text: '文本'
                    }, {
                        url: require('@/static/image/flow/flow3.jpg'),
                        text: '文本'
                    }, {
                        url: require('@/static/image/flow/flow.jpg'),
                        text: '文本'
                    }, {
                        url: require('@/static/image/flow/flow2.jpg'),
                        text: '文本'
                    }, {
                        url: 'https://pro-mixed-test.babycdn.com/base/digi/uploads/digi_demo/47/01/1679624701_7772.jpg',
                        text: '文本'
                    }, {
                        url: require('@/static/image/flow/flow.jpg'),
                        text: '文本'
                    },]
                    this.count(arr).then(() => {
                        resolve()
                    })
                }, 1000)
            })
        },
        count(arr) {
            return new Promise(async (resolve, reject) => {
                for (let i = 0; i < arr.length; i++) {
                    this.objItem = arr[i];
                    let span = await this.getItemHeight()
                    this.arrRowList.push(span)
                    if (i == arr.length - 1) {
                        this.arrList.push(...arr);
                        resolve()
                    }
                }
            })
        },
        getItemHeight() {
            return new Promise((resolve, reject) => {
                this.$nextTick(() => {
                    setTimeout(() => {
                        let query = uni.createSelectorQuery().in(this)
                        query.select('#count').boundingClientRect(ret => {
                            let span = 0;
                            let height = ret.height;
                            span = Math.floor(height / 5) + 2;
                            resolve(span)
                        }).exec();
                    }, 500)
                })
            })
        },
        loadTop() {
            this.arrRowList = [];
            this.arrList = [];
            this.getList().then(() => {
                this.$refs.list.endUpate()
            })
        },
        loadBottom() {
            this.getList().then(() => {
                this.$refs.list.endUpate()
            })
        }
    }
}
</script>

<style lang="scss" scoped>
.flow-wrap {
    width: 100%;
    height: 100%;

    .list {
        width: 100%;
        padding: 0 32rpx;
        box-sizing: border-box;
        /*column-gap: 24rpx;*/
        /*column-count: 2;*/

        display: grid;
        /*指定两列,自动宽度*/
        grid-template-columns: repeat(2, 1fr);
        /*横向间隔*/
        grid-column-gap: 24rpx;
        grid-row-gap: 0;
        /*是否自动补齐空白*/
        grid-auto-flow: row dense;
        /*base高度,grid-row基于此运算*/
        grid-auto-rows: 5px;

        .item {
            width: 100%;
            height: fit-content;
            overflow: hidden;
            box-sizing: border-box;
            padding: 10rpx;
            border: 1px solid #e2e2e2;
            border-radius: 12rpx;


            .img {
                width: 100%;
                display: block;
                border-radius: 12rpx;
            }

            .text {
                font-size: 28rpx;
                line-height: 40rpx;
            }
        }


    }

    .count-box {
        width: 90%;
        height: fit-content;
        position: fixed;
        top: 0;
        left: 0;
        z-index: -999;
        opacity: 0;

        .item {
            width: 50%;
            height: fit-content;
            overflow: hidden;
            box-sizing: border-box;
            padding: 10rpx;
            border: 1px solid #e2e2e2;
            border-radius: 12rpx;


            .img {
                width: 100%;
                display: block;
                border-radius: 12rpx;
            }

            .text {
                font-size: 28rpx;
                line-height: 40rpx;
            }
        }

    }
}
</style>