vue中实现瀑布流

vue中实现瀑布流瀑布流的参考实现可以看这篇博客:3种方式实现瀑布流布局1、利用css实现瀑布流/**flex布局实现*/.box{display:flex;align-items:center;flex-flow:columnwrap;height:100vh;//为啥要设置100vh才有效果}.item{border:1pxsolid#5592e5;margin:10px;width:calc(100%/3-20p

大家好,欢迎来到IT知识分享网。

瀑布流的参考实现可以看这篇博客:3种方式实现瀑布流布局

1、利用css实现瀑布流

/** flex布局实现 */

.box { 
   
  display: flex; 
  align-items: center; 
  flex-flow:column wrap; 
  height: 100vh; // 为啥要设置100vh才有效果
}
.item { 
   
    border: 1px solid #5592e5;
    margin: 10px;
    width: calc(100%/3 - 20px);
}

/** column布局实现 */
.box { 
   
  margin: 40px;
  column-count: 3;
  column-gap: 40px;
}
.item { 
   
  box-sizing: border-box;
  border: 1px solid #5592e5;
  margin-bottom: 40px;
  transition: all .5s; &:hover{ 
   
    transform: scale(1.1,1.1); 
  }
}

css实现有个缺点,它的实现原理是按列来排,先排满第一列,排不满的进入第二页,这个时候最后的呈现效果就可能存在最后一行时,中间有个块,显示不好。
请添加图片描述
另外还可能出现下面这种情况,该列的最后一个块的部分到了下一列首部。
请添加图片描述

2、利用js实现

可以自定义列数、行间距、列间距,注意margin是用户在对父组件设置了margin的情况下需要填写的,没有设置可以不填。

/** * @description: * @param {*} vm : this * @param {*} parent : 瀑布流组件 * @param {*} arg:{cols : 设置列数, margin:父元素设置的margin, vgap:块之间的水平间隙,hgap : 块之间的竖直间隙} * @return {*} */
function waterFall(vm, parent, arg) { 
   
  const divVGap = arg.vgap || 20
  const divHGap = arg.hgap || 20
  const columns = arg.cols || 3; //默认3列
  const margin = arg.margin || 0; 

  // 1 确定图片的宽度 - 滚动条宽度
  const pageWidth = parent.clientWidth - divVGap * columns - margin * 2 - 8;
  const itemWidth = parseInt(pageWidth / columns); //得到item的宽度
  const list = Array.from(parent.children)
  // 设置到item的宽度
  list.forEach((item, i) => { 
   
    item.style.width = itemWidth + 'px'; //设置到item的宽度
  })
  vm.$nextTick(() => { 
   
    setTimeout(() => { 
   
      const arr = []; // 存储每列当前高度
      list.forEach((item, i) => { 
   
        const height = item.clientHeight || item.offsetHeight;
        if (i < columns) { 
   
          // 2 第一行按序布局 
          item.setAttribute("style", `top:0; left:${ 
     (itemWidth) * i + divVGap * i}px; width:${ 
     itemWidth}px`)
          //将行高push到数组
          arr.push(height);
        } else { 
   
          // 其他行
          // 3 找到数组中最小高度 和 它的索引
          // 这种写法虽短,但没有下面的效率高
          // const minHeight = Math.min(...arr);
          // const index = arr.findIndex(item => item === minHeight);
          
          let minHeight = arr[0];
          let index = 0;
          for (let j = 0; j < arr.length; j++) { 
   
            if (minHeight > arr[j]) { 
   
              minHeight = arr[j];
              index = j;
            }
          }

          // 4 设置下一行的第一个盒子位置 top值就是最小列的高度
          // 1.8ms:耗时 
          // item.style.top = `${arr[index] + divHGap}px`
          // item.style.left = `${(itemWidth) * index + divVGap * index}px`
          
          // 0.3ms: 多个设置和合并成一个设置,性能更优,注意要加上width设置,此操作会把上面的width覆盖掉
          item.setAttribute("style", `top:${ 
     arr[index] + divHGap}px; left:${ 
     (itemWidth) * index + divVGap * index}px; width:${ 
     itemWidth}px`)

          // 5 修改最小列的高度
          // 最小列的高度 = 当前自己的高度 + 拼接过来的高度 + 竖直间隔
          arr[index] = arr[index] + height + divHGap;
        }
      })
    },100)
  })
}

//clientWidth 处理兼容性
function getClient() { 
   
  return { 
   
    width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
    height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
  }
}

export { 
    getClient, waterFall }

这里的vm.$nextTick 和 setTimeout都是为了正确的获取高度,但是这个处理不准确,图片的加载不知道什么时候结束,所以这里可以使用图片的懒加载插件,在图片加载之后进行setTimeOut中间的操作。如vue-lazyload

在vue文件使用

这里监控onsize的变化可以跟随页面变化而调整瀑布流。

<template>
    <div class="box" ref="box" id="box">
      <div class="item" ref="item">
        <img src="@/assets/image/not-exist@2x.png" alt="" />
      </div>
      <div class="item">
        <img src="@/assets/image/1@2x.png" alt="" />
      </div>
    
    </div>
</template>

<script> import { 
     waterFall } from '@/assets/js/waterfall' export default { 
     mounted() { 
     waterFall(this, this.$refs.box, { 
     margin:40, vgap:40, hgap:30}) // 页面尺寸改变时实时触发 window.onresize = () => { 
     //重新定义瀑布流 waterFall(this, this.$refs.box,{ 
     margin:40, vgap:40, hgap:30}) } }, } </script>

<style lang="scss" scoped> img{ 
     width: 100%; height: 100%; } .box { 
     margin: 40px; width: 100%; position:relative; box-sizing: content-box; } .item { 
     position: absolute; border: 1px solid #5592e5; transition: all .3s; cursor: pointer; &:hover{ 
     transform: scale(1.05,1.05); } } </style>

总结

这里只是简单的实现,后续还可以加上下拉加载等功能。
这里有些推荐瀑布流插件:https://www.cnblogs.com/ruruo/p/12938878.html,
vue-waterfall:这个要传入入瀑布流每项的宽高,这块可以通过上述代码的方式动态设置每个块的宽高。还可以自定义设置一些块位置变换时(页面缩小时)的过渡效果
vue-grid-layout : 提供自由拖拽的功能,官网上还有几个例子

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/20672.html

(0)
上一篇 2024-02-02 13:33
下一篇 2024-02-09 10:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信