1. 前言
瀑布流是非常流行的一种布局方式,所以今天来玩下
2. 是什么 what
瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。最早采用此布局的网站是Pinterest,逐渐在国内流行开来。国内大多数清新站基本为这类风格
哈哈以上文字摘抄自百度百科
3. 应用场景
图文混排的网站
4. 环境安装
需要的数据可以自己去爬取
5. 核心思想
多行等宽元素排列,后面的元素依次添加到其后,等宽不等高,
根据图片原比例缩放直至宽度达到我们的要求,依次按照规则放入指定位置。
6. 直接上代码 html
<div id="app"> <div class="list"> <ul class="col" v-for="col in waterFull"> <li v-for="good in col.goods"> <img :style="{height:good.height+'px'}" v-lazy="good.img" alt=""> <h3>{{good.author}}</h3> </li> </ul> </div> </div>
7. 瀑布流
let app = Vue.createApp({ data() { return { list } }, computed: { waterFull() { /* [{ h:10, goods:[{},{},{}] },{ h:10, goods:[{},{},{}] }] */ let arr = [];//记录每列信息 for (let i = 0; i < 5; i++) { arr.push({ h: 0,//记录每列高度 goods: []//记录每列的数据 }) } //分配商品 this.list.forEach(item => { // 找最低的列 arr.sort((a, b) => a.h > b.h ? 1 : -1) // ?w_h=236x334" // 叠加高度 let s = item.img.split("=")[1]; //236x334 let s2 = s.split("x"); //[236,334] let height = s2[1] / s2[0] * 200; //经过排序最低的列在 第一个位置 arr[0].h += height; // 一列的高度 // 记录当前图片高度 item.height = height; // 插入元素 arr[0].goods.push(item); //一列的数据 }) return arr; } } })
list 是我导入的外部数据
其中 图片链接格式为
"img": "https://xx.com/3P_/fw/480/webp?w_h=236x472"
核心在于如何找到当前行最低的那列,这个只能排序 对比
arr.sort((a, b) => a.h > b.h ? 1 : -1)
凡是返回1或者大于0的正数的时候就要交换位置
所以
a.h >b.h
的时候要交换位置 也就是1
8.结合懒加载
app.directive("lazy", { mounted(el, binding) { // 指定占位图 el.src = "./placeholder.png"; el.bindingVal = binding.value; let timer; el.scrollHandler = () => { clearTimeout(timer); timer = setTimeout(() => { let H = window.innerHeight; let ot = el.offsetTop; let st = document.body.scrollTop || document.documentElement.scrollTop; if (H + st > ot + 200) { // 设置真实路径 el.src = el.bindingVal; // 移除事件监听 window.removeEventListener("scroll", el.scrollHandler); } }, 100) } el.scrollHandler();//初始检测 window.addEventListener("scroll", el.scrollHandler); }, updated(el, binding) { // 存储新地址 el.bindingVal = binding.value; el.scrollHandler();//初始检测 } }) app.mount("#app")
具体懒加载思路可以参考react懒加载 ,代码其实都差不多
9. 瀑布流封装成组件
app.component("water-fall",{ props:["list","col"], template:` <div class="list"> <ul class="col" v-for="col in waterFull"> <li v-for="good in col.goods"> <img :style="{height:good.height+'px'}" v-lazy="good.img" alt=""> <h3>{{good.author}}</h3> </li> </ul> </div> `, computed: { waterFull() { let arr = [];//记录每列信息 for (let i = 0; i < this.col; i++) { arr.push({ h: 0, goods: [] }) } //分配商品 this.list.forEach(item => { // 找最低的列 arr.sort((a,b)=>a.h>b.h?1:-1) // 叠加高度 let s=item.img.split("=")[1]; let s2=s.split("x"); let height=s2[1]/s2[0]*200; arr[0].h+=height; // 记录当前图片高度 item.height=height; // 插入元素 arr[0].goods.push(item); }) return arr; } } })
单文件组件也一样没啥区别
再结合 懒加载的
v-lazy
的指令