JS基础特效(一)图片瀑布流

图片瀑布流是一种常见的页面特效,通过动态计算每一张图片的位置,在有限的空间内展示最多的图片

本案例实现的图片瀑布流是在图片宽度相等,高度不一致的情况下

实现思路

通过容器宽度与单张图片宽度计算出容器内可放置图片最大列数,根据最大列数生成对应的列高数组集合。监听所有图片onload事件,当图片加载成功时,找到列高集合中最小数及其索引(当前图片列高最小位置,即图片插入位置),图片插入后更新列高数组对应列数值;当视口发生变化时,即window.onresize事件触发时,重新计算最大列数、生成对应列高数组集合、计算每张图片具体位置。

具体实现代码
基本布局
<!DOCTYPE html>
<html>
    <head>
        <meta chartset="utf-8">
        <style>
            // 基础样式设置
            * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }
            
            #container {
                position: relative;
                font-size: 0;
            }
            
            #container img {
                position: absolute;
                width: 100;
                transition: all .5s;
            }
        </style>
        <title>图片瀑布流</title>
    </head>
    <body>
        <div id="container">
            <!--放置图片 -->
            <img src="http://via.placeholder.com/100x100" alt="图片">
            <img src="http://via.placeholder.com/100x200" alt="图片">
            <img src="http://via.placeholder.com/100x50" alt="图片">
            <img src="http://via.placeholder.com/100x60" alt="图片">
            
            <!-- 更多图片 -->
        </div>
    </body>
</html>
复制代码
JS代码
// 核心代码
class Falls {
  constructor (options = {}) {
    // 容器、容器宽度
    this.el = this.isElement(options.el) ? options.el : document.querySelector(options.el)
    this.elWidth = this.getElWidth(this.el)

    // 图片top right bottom left 偏移量
    this.offset = options.offset || 10
    
    // window.onresize方法防抖延迟
    this.delay = options.delay || 100

    // 图片集合、图片宽度
    this.imgs = Array.from(this.el.querySelectorAll('img'))
    this.imgWidth = this.getElWidth(this.imgs[0]) + this.offset

    // 容器内展示图片列数、列高度集合
    this.colCount = ~~(this.elWidth / this.imgWidth)
    this.colHeightList = []
    
    // 生成列高数组集合、监听图片onload、监听window.resize
    this.initColHeightList()
    this.bindImgOnload()
    this.onResize()
  }

  // 辅助方法
  isElement (el) {
    return el.nodeType === 1
  }

  getElWidth (el) {
    let width = el.style.width || el.clientWidth || el.offsetWidth
    return width
  }

  getElHeight (el) {
    let height = el.style.height || el.clientHeight || el.offsetHeight
    return height
  }

  bounce (callback) {
    let timer = null
    let that = this

    return function () {
      let arg = arguments

      if (timer) {
        clearTimeout(timer)
      }

      timer = setTimeout(() => {
        callback.apply(this, arg)
      }, that.delay)
    }
  }

  // 核心方法
  initColHeightList () {
    this.colHeightList = []

    for (let i = 0; i < this.colCount; i++) {
      this.colHeightList[i] = 0
    }
  }

  bindImgOnload () {
    this.imgs.forEach((img, i) => {
      img.addEventListener('load', (e) => {
        this.countPosition(e.target)
      })
    })
  }

  countPosition (el) {
    let minHeight = Math.min(...this.colHeightList)
    let minHeightIndex = this.colHeightList.indexOf(minHeight)

    el.style.top = minHeight + this.offset + 'px'
    el.style.left = minHeightIndex * this.imgWidth + 'px'

    this.colHeightList[minHeightIndex] += this.getElHeight(el) + this.offset
  }

  onResize () {
    let that = this

    window.addEventListener('resize', this.bounce(() => {
      // 重新计算
      that.elWidth = that.getElWidth(that.el)
      that.colCount = ~~(that.elWidth / that.imgWidth)

      that.initColHeightList()

      that.imgs.forEach(item => {
        that.countPosition(item)
      })
    }))
  }
}
复制代码
调用方式
const falls = new Falls({
    el: '#container', // 指定容器
    offset: 10, // 指定图片偏移量
    delay: 100 // 指定resize事件防抖延迟
})
复制代码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值