瀑布流的两种方法

7 篇文章 0 订阅

纯css

这是两列外层的盒子作为主控。(ps:他是先加载一列在加载一列,如果有分页也是如此,体验效果不好,如果没数字显示,没分页加载影响不大)

.box {
        width: 100%;
        -moz-column-count: 4;
        /* Firefox */
        -webkit-column-count: 4;
        /* Safari 和 Chrome */
        column-count: 2;//分为几列
        -moz-column-gap: 1em;
        -webkit-column-gap: 1em;
        column-gap: 5px;
    }

绝对定位

用vue和vant的list和图片懒加载加预览
css

@keyframes data-item-ani {
    0% {
        transform: scale(0.5);
    }
    100% {
        transform: scale(1);
    }
}

.data-list-box {
    position: relative;
    min-height: 100vh;
}

.img-div {
    position: absolute;
    /*width: 100%;*/
    overflow: auto;
    /*break-inside: avoid;*/
    margin-bottom: 2vw;
    animation: data-item-ani 0.4s;
    transition: left 0.6s, top 0.6s;
    transition-delay: 0.1s;
}

.img {
    width: 100%;
}

.finished-text1 {
    width: 100%;
    color: #969799;
    font-size: 14px;
    line-height: 50px;
    text-align: center;
}

.album-user {
    width: 100%;
    padding: 1%;
    display: -webkit-flex;
    display: flex;
}

.album-user-head {
    width: 10vw;
    height: 10vw;
    border-radius: 50%;
}

.album-user-name {
    line-height: 5vw;
    display: inline-block;
    margin-left: 2%;
}

.box2 {
    width: 100%;
    height: 100%;
}

.video-div {
    width: 96%;
    margin-left: 2%;
    margin-bottom: 2vw;
}

.video-div video {
    width: 100%;
    height: 30vw;
}

.van-sticky--fixed {
    width: 100%;
}

.data-list-box {
        min-height: 50vh;
    }

    .album-user-name {
        color: #646566;
        font-size: 0.12rem;
    }

    .img-div {
        display: none;
    }

html

<div id="app">
    <nav-back></nav-back>
    <van-tabs v-model="activeName" @click="onTabClick" sticky>
        <van-tab title="相册" name="1">
            <div class="box2">
                <van-pull-refresh v-model="loading" @refresh="onRefresh">
                    <van-list
                            v-model="loading"
                            :error.sync="error"
                            loading-text="加载中"
                            error-text="请求失败,点击重新加载"
                            :finished="finished"
                            @load="getImgList"
                            finished-text="没有更多了"
                            :offset='90'
                    >
                        <div class="data-list-box" id="data-list-box">
                            <div v-for="(item,indexImg) in imgList" :key="indexImg" class="img-div" :style="{width: boxWidth + 'px'}" :data-id="indexImg">
                                <img class="img" v-lazy="item.img" @click="onPreviewAvatar(item.img,indexImg)"
                                     :style="{width: '100%', height: item.imgHeight + 'px'}">
                                <div class="album-user">
                                    <img :src="item.head" class="album-user-head">
                                    <span class="album-user-name">
                                {{item.name}}
                                <br/>
                                {{item.time}}
                                </span>
                                </div>
                            </div>
                        </div>
                    </van-list>
                </van-pull-refresh>
            </div>
        </van-tab>
        <van-tab title="视频" name="2">
            <div class="box2">
                <van-pull-refresh v-model="loading2" @refresh="onRefresh2">
                    <van-list
                            v-model="loading2"
                            :finished="finished2"
                            @load="getVideoList"
                            finished-text="没有更多了"
                            :offset='30'
                    >
                        <div class="video-div" v-for="(itemVideo,indexVideo) in videoList" :key="indexVideo">
                            <video controls="" muted="muted" oncontextmenu="return false;" controlslist="nodownload"
                                   :poster="itemVideo.img" style="width: 100%; height:100%; object-fit: fill">
                                <source :src="itemVideo.video" type="video/mp4">
                            </video>
                            <div class="album-user">
                                <img :src="itemVideo.head" class="album-user-head">
                                <span class="album-user-name">
                                        {{itemVideo.name}}
                                        <br/>
                                        {{itemVideo.time}}
                                        </span>
                            </div>
                        </div>
                    </van-list>
                </van-pull-refresh>
            </div>
        </van-tab>
    </van-tabs>
    <!--    返回顶部-->
    <button-icon></button-icon>
</div>

js

Vue.use(vant.Lazyload, {
        lazyComponent: true
    });
    new Vue({
        el: '#app',
        data: {
            id: "{$id}",
            Page: 1,
            pageSize: 20, //每页加载数据数量

            imgList: [],
            error: false,
            loading: false,
            finished: false,
            Page2: 1,
            videoList: [],
            loading2: false,
            finished2: false,
            imagePreview: {
                images: []
            },
            activeName: '1',
            itemCount: 0, //上一次加载完成后的瀑布流item个数
            lastRowHeights: [0, 0], //最后一行标签的顶部间距+高度,2列

            boxMargin: 15, //每个item之间的边距
            boxWidth: 165 //每个item宽度px
        },
        created() {
            //当前瀑布流设置为两列,计算瀑布流每个item和图片的宽度
            let screenWidth = document.body.offsetWidth; //屏幕宽度
            this.boxWidth = (screenWidth - this.boxMargin * 3) / 2; //每个item的宽度
        },
        methods: {
            // 顶部标签点击事件
            onTabClick(name) {
                if (name == 1) {
                    this.onRefresh();
                } else {
                    this.onRefresh2();
                }
            },
            getImgList() {
                let that = this;
                this.$http.post('{:url("xxxxxx")}', {"page": that['Page'], "id": that['id']}, {
                    before: function () {
                        that['loading'] = true;
                    }
                }).then(function (res) {
                    if (res.body.code === 1) {
                        var resList = res.body.data['lists'];
                        that['Page'] += 1;
                        // that['imgList'] = that['imgList'].concat(resList);
                        resList.forEach(function (item) {
                            that['imagePreview']['images'] = that['imagePreview']['images'].concat(item.img);
                        });
                        if (res.body.data['finished'] === 1) {
                            that['finished'] = true;
                        }
                    } else {
                        that['finished'] = true;
                        vant.Toast.fail(res.body['msg']);
                    }
                    that['loading'] = false;
                    this.loadImagesHeight(resList); //模拟预加载图片,获取图片高度
                }).catch((res) => {
                    that['loading'] = false;
                    that['finished'] = true;
                    vant.Toast.fail('发生错误!');
                });
            },
            getVideoList() {
                let that = this;
                this.$http.post('{:url("xxxxxx")}', {"page": that['Page2'], "id": that['id']}, {
                    before: function () {
                        that['loading2'] = true;
                    }
                }).then(function (res) {
                    if (res.body.code === 1) {
                        var resList = res.body.data['lists'];
                        that['Page2'] += 1;
                        that['videoList'] = that['videoList'].concat(resList);


                        if (res.body.data['finished'] === 1) {
                            that['finished2'] = true;
                        }
                    } else {
                        that['finished2'] = true;
                        vant.Toast.fail(res.body['msg']);
                    }
                    that['loading2'] = false;
                }).catch((res) => {
                    that['loading2'] = false;
                    that['finished2'] = true;
                    vant.Toast.fail('发生错误!');
                });
            },
            onRefresh() {
                this.Page = 1;
                this.imgList = [];
                this['imagePreview']['images'] = [];
                this.itemCount = 0; //上一次加载完成后的瀑布流item个数
                this.lastRowHeights = [0, 0]; //最后一行标签的顶部间距+高度,2列

                this.finished = false;
                this.loading = true;
                this.getImgList();
            },
            onRefresh2() {
                this.Page2 = 1;
                this.videoList = [];
                this.finished2 = false;
                this.loading2 = true;
                this.getVideoList();
            },
            //图片预览
            onPreviewAvatar(images, startPosition) {
                vant.ImagePreview({
                    'images': this['imagePreview']['images'],
                    startPosition: startPosition,
                    closeable: true
                });
            },
            onChange(index) {
                this.imagePreview.index = index + 1;
            },
            //瀑布流
            loadImagesHeight(list) {
                var count = 0; //用来计数,表示是否所有图片高度已经获取
                list.forEach((item, index) => {
                    //创建图片对象,加载图片,计算图片高度
                    var img = new Image();
                    img.setAttribute('crossOrigin', 'anonymous');
                    img.src = item.img;
                    img.onload = img.onerror = (e) => {
                        count++;
                        if (e.type == 'load') { //图片加载成功
                            //计算图片缩放后的高度:图片原高度/原宽度 = 缩放后高度/缩放后宽度
                            list[index].imgHeight = Math.round(img.height * this.boxWidth / img.width);
                        } else { //图片加载失败,给一个默认高度50
                            list[index].imgHeight = 50;
                            console.log("index: ", index, ", 加载报错:", e);
                        }
                        //加载完成最后一个图片高度,开始下一步数据处理
                        if (count == list.length) {
                            this.resolveDataList(list);
                        }
                    };

                });
            },
            resolveDataList(list) { //处理数据
                //合并新老两个数组数据
                this.imgList = this.imgList.concat(list);
                //判断页面是否有数据
                // this.haveData = this.imgList.length > 0 ? 2 : 1;
                // this.loading = false; //上拉加载更多请求完成
                this.$nextTick(() => {
                    //渲染完成,计算每个item宽高,设置标签坐标定位
                    if (this.page == 1) {
                        this.setItemElementPosition();
                    } else {
                        setTimeout(() => {
                            //渲染完成,计算每个item宽高,设置标签坐标定位
                            this.setItemElementPosition();
                        }, 1000);
                    }
                });
            },
            //获取每个item标签高度,设置item的定位
            setItemElementPosition() {
                let parentEle = document.getElementById('data-list-box');
                let boxEles = parentEle.getElementsByClassName("img-div");
                for (let i = this.itemCount; i < (boxEles.length); i++) {
                    let tempEle = boxEles[i];
                    tempEle.style.display = "block";
                    //上一个标签最小高度的列索引
                    let curColIndex = this.getMinHeightIndex(this.lastRowHeights);
                    let boxTop = this.lastRowHeights[curColIndex] + this.boxMargin;
                    let boxLeft = curColIndex * (this.boxWidth + this.boxMargin) + this.boxMargin;
                    tempEle.style.left = boxLeft + 'px';
                    tempEle.style.top = boxTop + 'px';
                    this.lastRowHeights[curColIndex] = boxTop + tempEle.offsetHeight;
                    // console.log('i = ', i, ', lastRowHeights: ', this.lastRowHeights[curColIndex], ', boxTop: ', boxTop, ', eleHeight: ', tempEle.offsetHeight);
                }
                this.itemCount = boxEles.length;
                //修改父级标签的高度
                let maxHeight = Math.max.apply(null, this.lastRowHeights);
                parentEle.style.height = maxHeight + 'px';
                this.$toast.clear();
                // console.log("...boxEles: ", boxEles.length, ", maxH: ", maxHeight, ", loading: ", this.loading, ", finished: ", this.finished);
            },
            //获取数组中最小值的索引
            getMinHeightIndex(arr) {
                var minHeight = Math.min.apply(null, arr);
                for (let i = 0; i < arr.length; i++) {
                    if (arr[i] == minHeight) {
                        return i;
                    }
                }
            }
        }
    });
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UniApp是一种基于Vue.js框架的跨平台开发框架,可以用于开发iOS、Android、H5等多个平台的应用程序。瀑布是一种常见的页面布局方式,可以实现图片或卡片等元素的动态排列,使页面呈现出瀑布的效果。 在UniApp中实现瀑布布局可以通过以下步骤: 1. 引入瀑布组件:UniApp提供了一些瀑布组件,可以在页面中引入并使用。常用的瀑布组件有`uni-grid`和`uni-waterfall`。 2. 数据准备:准备好需要展示的数据,例如图片的URL、标题等信息。 3. 动态渲染:使用`v-for`指令将数据循环渲染到瀑布组件中,根据数据的不同来动态生成对应的元素。 4. 样式设置:通过CSS样式来设置瀑布元素的大小、间距等样式,以及容器的宽度和高度等。 下面是一个简单的示例代码,演示了如何在UniApp中实现瀑布布局: ```html <template> <view class="container"> <view class="waterfall"> <view class="item" v-for="(item, index) in dataList" :key="index"> <image :src="item.imageUrl" mode="aspectFill"></image> <text>{{ item.title }}</text> </view> </view> </view> </template> <script> export default { data() { return { dataList: [ { imageUrl: 'https://example.com/image1.jpg', title: 'Image 1' }, { imageUrl: 'https://example.com/image2.jpg', title: 'Image 2' }, { imageUrl: 'https://example.com/image3.jpg', title: 'Image 3' }, // 其他数据... ] }; } }; </script> <style> .container { width: 100%; height: 100%; } .waterfall { display: flex; flex-wrap: wrap; } .item { width: 50%; /* 每个元素占据的宽度,这里设置为一行两个元素 */ padding: 10px; } .item image { width: 100%; height: auto; } .item text { margin-top: 10px; } </style> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值