瀑布流布局的实现

13 篇文章 0 订阅
3 篇文章 0 订阅

做了一个图片管理系统,由于图片的高度不一,需要瀑布流布局。


ic365club

先看效果

在这里插入图片描述

技术需求

HTML、javascript、数学

固定数据

js函数是我参照其他网页的布局效果想出来的,这里我们先采用固定的列数来进行分析。
首先我们假设会有5列的图片,这样每行最多就会有5张图片。
我们将父容器的position设置为相对定位,图片的位置设置成绝对定位,然后在图片加载完成后js遍历修改图片的位置。

function rePosion(){
  // 假设固定有5列
  var nowNumber=5
  // 行数是后面校验了需要从0开始,因为第一行不需要加top的位置
  var nowRow=0
  // 获取所有的图片元素
  var imgs=document.querySelectorAll('.img-box')
  // 开始遍历
  imgs.forEach((ele,index)=>{
    // 先调整水平位置
    // 假设我们设置图片水平宽度为200,左右边距为16,那第一个的水平位置就是16,第二个水平位置就是16+200+16*2=254,第三个位置就是16+(200+16*2)*2=454
    ele.style.left=((index%nowNumber)*238)+16+'px'
    // 高度需要获取前一排的元素位置来确定,因为我们设置的是有5列,那么第6张图片就会换行。第6章图片top的位置就是第1张图片的底部位置加边距。规律就是top位置就是index比自己少5的底部位置加边距。那这样就好办了
    // 第一行的top位置不需要添加,所以这里增加一个行数判断
    if(index>=nowNumber){
      let nowHeight=document.querySelectorAll('.img-box')[index-nowNumber].offsetHeight
      nowHeight=nowHeight+document.querySelectorAll('.img-box')[index-nowNumber].offsetTop
      // 上一行,同一列的底部像素位置等于:其top位置(offsetTop)+其高度(offsetHeight)
      // 设置图片的top位置,再加上一个边距就可以了
      ele.style.top=nowHeight+12+'px'
    }else{
      ele.style.top=12+'px'
    }
    // 给行数的序号增加,这里没有用到这个参数,但是避免会用到,所以还是计算一下
    if(index>=(nowNumber-1) && index%(nowNumber-1)==0){
      nowRow++
      // console.log(nowRow)
    }
  })
}

1.先调整水平位置
假设我们设置图片水平宽度为200,左右边距为16,那第一个的水平位置就是16,第二个水平位置就是16+200+162=254,第三个位置就是16+(200+162)*2=454

2.高度需要获取前一排的元素位置来确定,因为我们设置的是有5列,那么第6张图片就会换行。第6章图片top的位置就是第1张图片的底部位置加边距。规律就是top位置就是index比自己少5的底部位置加边距。那这样就好办了
第一行的top位置不需要添加,所以这里增加一个行数判断

3.上一行,同一列的底部像素位置等于:其top位置(offsetTop)+其高度(offsetHeight)
设置图片的top位置,再加上一个边距就可以了

这样就完成了一个固定列数的函数了,现在我们只需根据动态获取父容器的宽度来除以图片的宽度,向下取整就看获的动态的列数了。

动态数据

这样就完成了一个固定列数的函数了,现在我们只需根据动态获取父容器的宽度来除以图片的宽度,向下取整就看获的动态的列数了。

// 计算出目前行的大小
var imgBoxWidth=document.querySelector('.list-box').offsetWidth
// 动态获取列数,这里我设置图片宽度加边距为246
var nowNumber=Math.ceil(imgBoxWidth/246)-1

防抖节流

既然我们已经把上面的函数做成动态获取了,那肯定需要有一个执行的节点。我这里假设的节点是再图片加载完成获取窗口大小发生改变。
这里就需要我们做一个防抖函数。【需要先理解闭包】

我们真正执行的函数会是防抖函数计算后返回的闭包函数。
所以我们需要先执行防抖函数,获取到动态调整位置函数的闭包,再在时间节点执行返回的闭包函数。

function debounce(func,delay=500){
  // let timer // 实在不行只能报timer放到全局了
  return function(){
    let context=this;
    let args=arguments;
    if(timer) clearTimeout(timer);
    timer=setTimeout(()=>{
      func.apply(this,args)
    },delay)
  }
}

这是防抖函数,比较简单。现在的模式是将timer变量全局化,这样我们直接执行防抖函数就可以。
这样是可以达到效果的,但是这样有点不太对。

function debounce(func,delay=500){
  let timer // timer放到闭包
  return function(){
    let context=this;
    let args=arguments;
    if(timer) clearTimeout(timer);
    timer=setTimeout(()=>{
      func.apply(this,args)
    },delay)
  }
}

我们需要将timer放到闭包,然后在哪里执行以下防抖函数,在声明一个变量来接收防抖函数返回的函数。

var refreshPosion=debounce(rePosion,100)
// console.log(refreshPosion)
// 我们最好真正需要执行的其实是refreshPosion()
防抖常见错误

常见的错误:直接在防抖的地方执行debounce函数,但其实它只是作为一层计算,返回一个函数,真正执行的是返回的这个函数。

js闭包

关于闭包其原理大家自行了解吧,这里就不拓展了。简单的模式就是函数里会返回一个函数,函数里面的变量会被返回的函数带着跑。

优化

大家在使用的时候可能会发现问题了,就是防抖里面会有几秒的延时,但是我们需要的就是这个延时,但是这个延时会导致第一个延时时页面布局像是bug一样。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H7xIgy9d-1641657178486)(/article/img/AI22eq010h08.png)]
所以我们在延时前也需要调用一次reposion()。一般的我会在ajax请求完成之后执行一次

this.$nextTick(()=>{
	this.rePosion()
})

——————————

转载请注明出处!!!
本文首发:https://www.ic365club.com
ic365club是知识分享和学习交流的扁平化平台,欢迎广大爱好学习的伙伴一起加入

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

圈点Studio

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值