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

相关文章
相关标签/搜索