美文网首页
uniapp-小程序-瀑布流布局-支持下拉刷新上拉加载更多

uniapp-小程序-瀑布流布局-支持下拉刷新上拉加载更多

作者: 银河系小前端 | 来源:发表于2020-06-08 08:39 被阅读0次

    uniapp-小程序-瀑布流布局-支持下拉刷新上拉加载更多

    主要思路:

    • 将父组件传递进来的list分为两组,leftList和rightList,初始化为空数组
    • 页面布局分为左右两侧,左侧渲染leftList的数据,右侧渲染rightList的数据,并初始化左右两栏的高度为0
    • 利用image标签中的load事件,在图片加载的时候,获取到图片的实际尺寸,计算出要显示的高度。比较两栏的高度,将对应的数据加到leftList或者rightList

    我们在组件中写一个两列的布局,图片的宽度设定为345rpx,文字的高度定为100rpx,下边距定为20rpx,给image绑定一个load方法,onImageLoad,这个组件的核心就是这个方法。

    //wterfall
    <template>
        <view class="waterfall">
            <view class="left">
                <block v-for="(item, index) in leftList" :key="index">
                    <view class="waterfall-item">
                        <image :src="item.src" mode="widthFix" lazy-load @load="onImageLoad"></image>
                        <view class="title">{{ item.title }}</view>
                    </view>
                </block>
            </view>
            <view class="right">
                <block v-for="(item, index) in rightList" :key="index">
                    <view class="waterfall-item">
                        <image :src="item.src" mode="widthFix" lazy-load @load="onImageLoad"></image>
                        <view class="title">{{ item.title }}</view>
                    </view>
                </block>
            </view>
        </view>
    </template>
    
    <style lang="scss">
    .waterfall {
        width: 100%;
        display: flex;
        justify-content: space-between;
        padding: 0 20rpx;
        box-sizing: border-box;
        .left,
        .right {
            .waterfall-item {
                width: 345rpx;
                margin-bottom: 20rpx;
                background-color: pink;
                box-sizing: border-box;
                image {
                    width: 345rpx;
                    display: block;
                }
                .title {
                    width: 345rpx;
                    height: 100rpx;
                    overflow: hidden;
                }
            }
        }
    }
    </style>
    
    

    可以看到,上面有两个view,分别是left和right,分别渲染的是leftList和rightList里面的数据,那么这两个数据是怎么来的呢?我们在组件中定义一个prop:

    props: {
            list: {
                type: Array,
                default: []
            }
    }
    

    这个list是通过父组件传递过来的,也就是你原始的数据,我们在组件中再声明几个变量,并在created的时候,将list中的第一个数据存入到leftList中

    data() {
            return {
                leftList: [],
                rightList: [],
                itemIndex: 0,
                leftHeight: 0,
                rightHeight: 0
            };
    },
    created() {
            this.leftList = [this.list[0]]; //第一张图片入栈
    },
    

    然后就是最重要的onImageLoad方法了

    onImageLoad(e) {
                if (!e) {
                    console.log('无图片!!!!');
                    return;
                }
                let imgH = (e.detail.height / e.detail.width) * 345 + 100 + 20; //图片显示高度加上下面的文字的高度100rpx,加上margin-bottom20rpx
                let that = this;
                if (that.itemIndex === 0) {
                    that.leftHeight += imgH; //第一张图片高度加到左边
                    that.itemIndex++;
                    that.rightList.push(that.list[that.itemIndex]); //第二张图片先入栈
                } else {
                    that.itemIndex++;
                    //再加高度
                    if (that.leftHeight > that.rightHeight) {
                        that.rightHeight += imgH;
                    } else {
                        that.leftHeight += imgH;
                    }
                    if (that.itemIndex < that.list.length) {
                        //下一张图片入栈
                        if (that.leftHeight > that.rightHeight) {
                            that.rightList.push(that.list[that.itemIndex]);
                        } else {
                            that.leftList.push(that.list[that.itemIndex]);
                        }
                    }
                }
        }
    

    上面注释的也比较清楚了,首先要将第一张图入栈,这个时候onImageLoad才会返回图片信息,不然的话是没有图片的,在onImageLoad方法执行的时候,先计算出图片的显示高度,然后计算leftHeight和rightHeight的高度,再将下一张图入栈。

    上拉加载更多、下拉刷新

    上拉加载更多的时候,监听list的变化,list的新的值会比旧的值length更大,这个时候将新添加进来的值的第一个数据先入栈,相当于是首次加载的时候第一个数据先放到leftList。

        watch: {
            list(n, o) {
                let that = this;
                // console.log('=====watch  list=====', n, o);
                let ol = o.length;
                let nl = n.length;
                if (nl > ol) {
                    if (this.leftHeight > this.rightHeight) {
                        that.rightList.push(that.list[ol]);
                    } else {
                        that.leftList.push(that.list[ol]);
                    }
                    this.onImageLoad();
                }
            }
        },
    

    下拉刷新的时候有一点不一样,需要先将组件销毁掉,再重新渲染,可以在父组件中用v-if判断是否要销毁,父组件中的代码:

    <waterFall v-if="goodsList.length > 0" :list="goodsList"></waterFall>
    
    onPullDownRefresh() {
            this.goodsList = [];
            setTimeout(() => {
                this.goodsList = [...list];
            }, 500);
    
            uni.stopPullDownRefresh();
    }
    

    大致就是这样,我觉得还不够好,但在我的项目中也是够用了,贴上完整的代码:

    //waterfall.vue
    <template>
        <view class="waterfall">
            <view class="left">
                <block v-for="(item, index) in leftList" :key="index">
                    <view class="waterfall-item">
                        <image :src="item.src" mode="widthFix" lazy-load @load="onImageLoad"></image>
                        <view class="title">{{ item.title }}</view>
                    </view>
                </block>
            </view>
            <view class="right">
                <block v-for="(item, index) in rightList" :key="index">
                    <view class="waterfall-item">
                        <image :src="item.src" mode="widthFix" lazy-load @load="onImageLoad"></image>
                        <view class="title">{{ item.title }}</view>
                    </view>
                </block>
            </view>
        </view>
    </template>
    
    <script>
    export default {
        name: 'water-fall',
        props: {
            list: {
                type: Array,
                default: []
            }
        },
        watch: {
            list(n, o) {
                let that = this;
                // console.log('=====watch  list=====', n, o);
                let ol = o.length;
                let nl = n.length;
                if (nl > ol) {
                    if (this.leftHeight > this.rightHeight) {
                        that.rightList.push(that.list[ol]);
                    } else {
                        that.leftList.push(that.list[ol]);
                    }
                    this.onImageLoad();
                }
            }
        },
        data() {
            return {
                leftList: [],
                rightList: [],
                itemIndex: 0,
                leftHeight: 0,
                rightHeight: 0
            };
        },
        created() {
            this.leftList = [this.list[0]]; //第一张图片入栈
        },
        destroyed() {
            console.log('destroy');
        },
        methods: {
            onImageLoad(e) {
                if (!e) {
                    console.log('无图片!!!!');
                    return;
                }
                let imgH = (e.detail.height / e.detail.width) * 345 + 100 + 20; //图片显示高度加上下面的文字的高度100rpx,加上margin-bottom20rpx
                let that = this;
                if (that.itemIndex === 0) {
                    that.leftHeight += imgH; //第一张图片高度加到左边
                    that.itemIndex++;
                    that.rightList.push(that.list[that.itemIndex]); //第二张图片先入栈
                } else {
                    that.itemIndex++;
                    //再加高度
                    if (that.leftHeight > that.rightHeight) {
                        that.rightHeight += imgH;
                    } else {
                        that.leftHeight += imgH;
                    }
                    if (that.itemIndex < that.list.length) {
                        //下一张图片入栈
                        if (that.leftHeight > that.rightHeight) {
                            that.rightList.push(that.list[that.itemIndex]);
                        } else {
                            that.leftList.push(that.list[that.itemIndex]);
                        }
                    }
                }
            }
        }
    };
    </script>
    
    <style lang="scss">
    .waterfall {
        width: 100%;
        display: flex;
        justify-content: space-between;
        padding: 0 20rpx;
        box-sizing: border-box;
        .left,
        .right {
            .waterfall-item {
                width: 345rpx;
                margin-bottom: 20rpx;
                background-color: pink;
                box-sizing: border-box;
                image {
                    width: 345rpx;
                    display: block;
                }
                .title {
                    width: 345rpx;
                    height: 100rpx;
                    overflow: hidden;
                }
            }
        }
    }
    </style>
    
    
    <template>
        <view>
            <waterFall v-if="goodsList.length > 0" :list="goodsList"></waterFall>
        </view>
    </template>
    
    <script>
    const list = [
        { src: 'cardBg7.png', title: '1、非常好看的额图片,快起来这里买东西' },
        { src: 'ios.png', title: '2、这段文字要少' },
        { src: 'home_banner1.jpg', title: '3、大段文字展示' },
        { src: 'IMG17.jpeg', title: '4、特朗普的眼镜' },
        { src: 'cardBg5.png', title: '5、非常好看的额图片,快起来这里买东西' },
        { src: 'operation_pt_img.png', title: '6、非常好看的额图片,快起来这里买东西' }
    ];
    import waterFall from '@/components/waterfall.vue';
    export default {
        components: {
            waterFall
        },
        data() {
            return {
                goodsList: [...list] //商品列表
            };
        },
        onReachBottom() {
            if (this.goodsList.length > 29) {
                uni.showToast({
                    title: '30条全部加载完毕!',
                    icon: 'none'
                });
            } else {
                this.goodsList = this.goodsList.concat(list);
            }
        },
        onPullDownRefresh() {
            this.goodsList = [];
            setTimeout(() => {
                this.goodsList = [...list];
            }, 500);
    
            uni.stopPullDownRefresh();
        }
    };
    </script>
        
    

    相关文章

      网友评论

          本文标题:uniapp-小程序-瀑布流布局-支持下拉刷新上拉加载更多

          本文链接:https://www.haomeiwen.com/subject/qcfbzhtx.html