瀑布流布局的写法原理

瀑布流

  • 图片的宽高比例不同, 导致每个元素的宽度相同, 高度不同. 采用非规则的盒子布局方案.
  • 实现方式: 需要通过 JS 来遍历每个元素, 计算这些元素的摆放位置.
  • 利用 绝对定位 来实现布局
    在这里插入图片描述

制作步骤:

  1. 先实现第一行页面的排列

  2. 后续的元素在摆放时, 需要找到已经摆放的元素中每一列中最下方的中, 最矮的那个, 放在其下方

流程

1.从接口数据中拿到图片的宽高

1.1为什么服务器要提供宽和高?
  • 因为我们的图片属于网络图, 涉及到异步加载, 只有加载完毕后才能得到图片的宽高, 无法满足当前的需求
    const { cover, favorite, head_icon, name, title, width, height } = value
1.2 图片有两种宽度, 这种宽高比一定相同, 应该等比例计算
    1. 原始宽高
    1. 显示宽高
  const img_w = 242.5 //显示的宽度
          const img_h = img_w * height / width  //显示时的高度

2.完成第一行

// 对所有已添加到页面上的li 进行位置的计算
// each 类似数组的 forEach, 是jQuery提供的用于遍历查询到的元素的方法
// 参数1: 序号; 参数2: 元素;

  // 声明1个数组, 存放已经布局完毕的元素(每一列中最下方的那个), 便于后续查找这些元素中最矮的

const els = []

$('.note-content>li').each((i, el) => {
	 console.log(i, el)
        // 读取宽度
        const w = $(el).width()
        // 对前4个元素进行布局: 即序号 0 1 2 3 的元素
        if (i < 4) {
          $(el).css({ left: i * w + i * 10, top: 0 })
          els.push(el) // 存储在数组中
        } else { // 非前四个}
}

3.对非前四个元素进行布局

// 这里是对 非前4个元素进行布局的位置. 每次布局都要找到已经布局的元素中, 底部最矮的

3.1 创建一个getBottom函数 (图片顶部加图片高度)
// 获取某个元素的底部偏移量 = 元素的top值 + 元素的高
  function getBottom(el) {
    // 元素的顶部 top
    const top = $(el).css('top') // 大概: '10px'   
    // 获取高度
    const height = $(el).height() // 获取的是值, 例如 20
    // console.log({ top, height })
    // 如何把 '10px' 转为数字 10
    // 通过 parseFloat 转化
    return parseFloat(top) + height
  }

3.2 找到最小的元素让作为本列的最下方

else {
 	// 默认设置数组中 第一个元素最小
	let el_min = els[0]
	
 	els.forEach(elem => {
            // var b = getBottom(elem)
            // console.log('元素底部:', b)
            // 判断: 当前遍历的元素 和 已知最小的元素 哪个更小
            if (getBottom(elem) < getBottom(el_min)) {
              el_min = elem // 把当前元素设置为最小的元素
            }
          })
           console.log('找到最小元素:', el_min);

          $(el).css({
            left: $(el_min).css('left'), // 左侧对齐
            top: getBottom(el_min) + 10, // 较小元素底部 下方10px
          })

          // 新的元素摆放后, 则其称为当前列中最下方的元素, 则需要对应替换掉 els 数组中的元素
          // 1. 获取当前最小元素的序号
          const index = els.indexOf(el_min)
          // 2. 把此元素替换成新增的元素, 作为这一列中最下方的
          els.splice(index, 1, el)
}

4.解决绝对定位的高度坍塌

原理:找到最大的元素 这个最大的元素的高度就是父元素的高度

 // 由于所有的li都是绝对定位方式, 导致其父元素 高度坍塌, 影响下方的 脚部栏位置
      // 手动找到 els 数组中, 底部最大的那个, 这就是父元素应该具备的高度
      // 然后js 设置给父元素即可
      let el_max = els[0]

      els.forEach(el => {
        if (getBottom(el) > getBottom(el_max)) {
          el_max = el //如果遍历的元素 比 当前最大的 还要大, 就替换
        }
      })
      // 把这个最大元素的底部位置, 设置为父元素的高
      $('.note-content').height(
        getBottom(el_max)
      )

整体代码

$(function () {
  // 获取某个元素的底部偏移量 = 元素的top值 + 元素的高
  function getBottom(el) {
    // 元素的顶部 top
    const top = $(el).css('top') // 大概: '10px'   
    // 获取高度
    const height = $(el).height() // 获取的是值, 例如 20
    // console.log({ top, height })
    // 如何把 '10px' 转为数字 10
    // 通过 parseFloat 转化
    return parseFloat(top) + height
  }

  function getData(p) {
    var url = 'https://serverms.xin88.top/note?page=' + p
    $.get(url, data => {
      console.log('笔记数据:', data)
      $('.note-content').append(
        data.data.map(value => {
          // 为什么服务器要提供宽和高?
          // 因为我们的图片属于网络图, 涉及到异步加载, 只有加载完毕后才能得到图片的宽高, 无法满足当前的需求
          const { cover, favorite, head_icon, name, title, width, height } = value

          // 图片有两种宽度, 这种宽高比一定相同, 应该等比例计算
          // 1. 原始宽高
          // 2. 显示宽高
          const img_w = 242.5 //显示的宽度
          const img_h = img_w * height / width  //显示时的高度

          return `<li>
          <img src="./assets/img/note/${cover}" 
          style="width:${img_w}px; height:${img_h}px" alt="">
          <p>${title}</p>
          <div>
            <div>
              <img src="./assets/img/note/${head_icon}" alt="">
              <span>${name}</span>
            </div>
            <span>${favorite}</span>
          </div>
        </li>`
        })
      )

      // 对所有已添加到页面上的li 进行位置的计算
      // each 类似数组的 forEach, 是jQuery提供的用于遍历查询到的元素的方法
      // 参数1: 序号;  参数2: 元素;

      // 声明1个数组, 存放已经布局完毕的元素(每一列中最下方的那个), 便于后续查找这些元素中最矮的
      const els = []

      $('.note-content>li').each((i, el) => {
        console.log(i, el)
        // 读取宽度
        const w = $(el).width()
        // 对前4个元素进行布局: 即序号 0 1 2 3 的元素
        if (i < 4) {
          $(el).css({ left: i * w + i * 10, top: 0 })
          els.push(el) // 存储在数组中
        } else {
          // 这里是对 非前4个元素进行布局的位置. 每次布局都要找到已经布局的元素中, 底部最矮的

          // 默认设置数组中 第一个元素最小
          let el_min = els[0]

          els.forEach(elem => {
            // var b = getBottom(elem)
            // console.log('元素底部:', b)
            // 判断: 当前遍历的元素 和 已知最小的元素 哪个更小
            if (getBottom(elem) < getBottom(el_min)) {
              el_min = elem // 把当前元素设置为最小的元素
            }
          })

          console.log('找到最小元素:', el_min);

          $(el).css({
            left: $(el_min).css('left'), // 左侧对齐
            top: getBottom(el_min) + 10, // 较小元素底部 下方10px
          })

          // 新的元素摆放后, 则其称为当前列中最下方的元素, 则需要对应替换掉 els 数组中的元素
          // 1. 获取当前最小元素的序号
          const index = els.indexOf(el_min)
          // 2. 把此元素替换成新增的元素, 作为这一列中最下方的
          els.splice(index, 1, el)

        }
      })

      // 由于所有的li都是绝对定位方式, 导致其父元素 高度坍塌, 影响下方的 脚部栏位置
      // 手动找到 els 数组中, 底部最大的那个, 这就是父元素应该具备的高度
      // 然后js 设置给父元素即可
      let el_max = els[0]

      els.forEach(el => {
        if (getBottom(el) > getBottom(el_max)) {
          el_max = el //如果遍历的元素 比 当前最大的 还要大, 就替换
        }
      })
      // 把这个最大元素的底部位置, 设置为父元素的高
      $('.note-content').height(
        getBottom(el_max)
      )
    })
  }
  getData(1)
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值