js+CSS简单实现瀑布流布局

 更新时间:2023年11月21日 10:59:18   作者:sherlockkid7  
瀑布流布局,是一种视觉表现为参差不齐的多栏布局,常用于内容以图片为主的页面展示,本文将使用css和js两种方式来实现瀑布流布局,需要的可以参考下

前言

瀑布流布局,是一种视觉表现为参差不齐的多栏布局。常用于内容以图片为主的页面展示,图片等宽不等高,每行从左到右排满后,后面的元素依次添加至短的一列其后。随着页面向下滚动,还会不断加载数据并添加到当前尾部,视觉上显得错落有致不拘一格。今天使用css和js两种方式来实现瀑布流布局

css实现瀑布流布局

该方式实现的瀑布流布局其中的内容数据是固定的,主要利用了 CSS 的多列属性 columns

页面结构:创建容器container,该容器包裹所有用于展示的元素item(图片和标题)

  <div class="container">
    <div class="item">
      <img src="..."/>
      <h2>...</h2>
    </div>
    ...
</div>

给容器container设置宽度,并居中显示;控制其中的内容分成3列columns: 3;,列与列之间的距离为20pxcolumn-gap: 20px;

每个item元素,设置属性break-inside: avoid;, 避免在多列布局中元素内容被分割(元素的内容被自动断开,图片在一列尾部,文字在下一列的头部)

.container {
  width: 1200px;
  margin: 20px auto;
  columns: 3;
  column-gap: 20px;
}

.container .item {
  width: 100%;
  break-inside: avoid;
  margin-bottom: 20px;
}
.container .item img{
  width: 100%;
}

小结:根据上图可以看出CSS的多列布局实现的瀑布流是从上到下,再从左到右的顺序排列元素,适用于对于元素顺序没有要求,且元素数据固定的情况

js实现瀑布流布局

思路:

每个元素使用绝对定位的方式,动态的设置相应的top,left值进行排列,先计算一行能够容纳几列元素,第一行元素直接设置top为0,left为索引乘以(元素宽度 + 间隙)进行排列,后面的元素排列,需要找出所有列中高度最小的那一列,将元素添加至高度最小的那一列后面,直至所有元素添加完毕。

创建一个容器container,用于存放展示的元素。并设置css为相对定位,其中展示的元素为绝对定位

<div id="container"></div>

计算页面一行能容纳几列元素

列数 = 页面的宽度 / (元素的宽度+元素之间的间隙 ) column = pageWidth / (itemWidth + gap);

注:页面的宽度这里设置的是body的宽度(使用css控制了最大宽度和最小宽度)

创建createElement函数,用来动态创建组成瀑布流的元素块(包含图片和标题),并在请求数据成功后调用添加到页面中,并进行瀑布流布局

function createElement(itemData) {
  return new Promise((resolve, reject) => {
    let div = document.createElement('div')
    div.innerHTML = `...`
    div.className = 'item'
    // 监听图片的load事件
    div.querySelector('img').addEventListener('load', () => {
      resolve(div)
    })
  })
}

// 获取喵咪的数据
let page = 1  //请求数据的页码
let isReq = false  //设置节流阀,处于请求过程中,则不再请求数据
function loadNewData() {
  if (isReq) return
  isReq = true
  getData()
    .then(data => {
      // 处理新的数据
      let items = data
      let promises = items.map(item => createElement(item))
      Promise.all(promises).then(nodes => {
        let frag = document.createDocumentFragment()
        isReq = false
        page++
        nodes.forEach(node => {
          frag.appendChild(node)
          Node.push(node)
        })
        document.getElementById('container').appendChild(frag)
        waterfall(Node)
      })
    })
    
}

注:遇到获取元素块高度不正确的问题

因为图片可能还没有完全加载,获取的元素块高度就只是h4标签的高度。因此需要在图片加载完成后再获取元素的高度。

a.通过监听图片的 load 事件,当事件触发时,表示图片已经加载完成,返回创建的div元素

b.在获取数据loadNewData()函数中,对返回的数据执行创建元素方法,并使用Promise.all()对由返回的div元素(Promise 实例)组成的Promise 数组进行处理,当每个Promise实例的状态变为 fulfilled(所有图片都加载完成),就执行瀑布流布局

创建waterfall函数,实现瀑布流

接收元素数组,然后对每个元素进行布局。如果元素在第一行,那么它的顶部位置就是 0,左侧位置就是它的索引乘以(元素宽度 + 间隙)。如果元素不在第一行,那么我们首先找出高度最小的列,然后将元素放在这个列的下方,并更新这个列的高度。

function waterfall(items) {
  for (var i = loaded; i < items.length; i++) {
    let item = items[i]
    let height = item.offsetHeight
    if (i < columns) {
      //满足这个条件则说明在第一行
      item.style.top = 0
      item.style.left = (itemWidth + gap) * i + 'px'
      heightArr.push(height)
    } else {
      //其他行,先找出最小高度列的索引
      const minIndex = getMinIndex(heightArr)
      //top值就是最小列的高度+gap
      const top = heightArr[minIndex] + gap
      item.style.top = top + 'px'
      item.style.left = minIndex * (itemWidth + gap) + 'px'

      //修改原本最小列的高度 
      heightArr[minIndex] = top + height
    }
    loaded = items.length
  }
}

//用于获取heightArr数组中值最小的列的索引。
const getMinIndex = (array) => {
  const min = Math.min.apply(null, array)
  return array.indexOf(min)
}

监听页面滚动,当未显示的元素内容小于屏幕高度的一大半(这里设置的0.7,因为数据加载比较慢,一般设置成0.5就可以),就需要加载新数据进行展示

window.addEventListener('scroll', lazy)
function lazy() {
 const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
 const documentHeight = document.documentElement.scrollHeight
  // 未显示的内容 = 文档(内容)高度-滚动高度-屏幕高度
  if (documentHeight - scrollTop - clientHeight < 0.7 * clientHeight) {
    loadNewData()
  }
}

小结:

a. 简单封装的请求数据方法getData()没有展示出来,请求的接口是从网上找的(地址),一次只能加载10张,并且加载很慢,可以自行查找接口。

b. 需要定义的变量

根据以上基本可以实现瀑布流了,排列顺序和滚动页面加载数据也比较符合一般情况

以上就是js+CSS简单实现瀑布流布局的详细内容,更多关于js瀑布流布局的资料请关注脚本之家其它相关文章!

相关文章

  • 微信小程序结合Storage实现搜索历史效果

    微信小程序结合Storage实现搜索历史效果

    这篇文章主要为大家详细介绍了微信小程序结合Storage实现搜索历史效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • 5分钟理解JavaScript中this用法分享

    5分钟理解JavaScript中this用法分享

    这篇文章介绍了5分钟理解JavaScript中this用法,有需要的朋友可以参考一下
    2013-11-11
  • JS简单实现点击按钮或文字显示遮罩层的方法

    JS简单实现点击按钮或文字显示遮罩层的方法

    这篇文章主要介绍了JS简单实现点击按钮或文字显示遮罩层的方法,涉及javascript鼠标事件响应及页面元素属性动态操作相关实现技巧,需要的朋友可以参考下
    2017-04-04
  • 详解javascript 正则表达式之分组与前瞻匹配

    详解javascript 正则表达式之分组与前瞻匹配

    本文主要讲解javascript 的正则表达式中的分组匹配与前瞻匹配的,需要对正则的有基本认识,本人一直对两种匹配模棱不清,还有不清楚的朋友跟随脚本之家小编一起看看吧
    2018-05-05
  • JavaScript中遍历跳出循环方法总结

    JavaScript中遍历跳出循环方法总结

    这篇文章主要给大家介绍了关于JavaScript中遍历跳出循环方法的相关资料,一想到想到循环的跳出,立马就会想到三个关键,break、return、continue,在业务中也会需要在遍历的时候退出循环,需要的朋友可以参考下
    2023-12-12
  • 微信小程序实现多行文字超出部分省略号显示功能

    微信小程序实现多行文字超出部分省略号显示功能

    这篇文章主要介绍了微信小程序实现多行文字 超出部分省略号显示功能,比如设置只显示2行,超出部分省略号显示,本文通过实例代码给大家介绍,需要的朋友可以参考下
    2019-10-10
  • 浅谈js多维数组和hash数组定义和使用

    浅谈js多维数组和hash数组定义和使用

    下面小编就为大家带来一篇浅谈js多维数组和hash数组定义和使用。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • js 手机号码合法性验证代码集合

    js 手机号码合法性验证代码集合

    下面是JS验证电话号码的代码,很实用,献给大家
    2012-09-09
  • javascript 选择文件夹对话框(web)

    javascript 选择文件夹对话框(web)

    web程序开发中经常会遇见选择文件夹的时候,这对于web程序员是一件麻烦的事情,由于本地安全限制JS不能访问本地文件,所以选择文件夹一般都避而不谈,笔者在写一个程序的时候也遇见了同样的问题,开始尝试使用JS来遍历文件,结果都没有成功
    2009-07-07
  • JavaScript中transform实现数字翻页效果

    JavaScript中transform实现数字翻页效果

    本文主要介绍JavaScript中利用transform实现数字翻页效果的实例,具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03

最新评论