大家好,欢迎来到IT知识分享网。
瀑布流的参考实现可以看这篇博客:3种方式实现瀑布流布局
1、利用css实现瀑布流
/** flex布局实现 */
.box {
display: flex;
align-items: center;
flex-flow:column wrap;
height: 100vh; // 为啥要设置100vh才有效果
}
.item {
border: 1px solid #5592e5;
margin: 10px;
width: calc(100%/3 - 20px);
}
/** column布局实现 */
.box {
margin: 40px;
column-count: 3;
column-gap: 40px;
}
.item {
box-sizing: border-box;
border: 1px solid #5592e5;
margin-bottom: 40px;
transition: all .5s; &:hover{
transform: scale(1.1,1.1);
}
}
css实现有个缺点,它的实现原理是按列来排,先排满第一列,排不满的进入第二页,这个时候最后的呈现效果就可能存在最后一行时,中间有个块,显示不好。
另外还可能出现下面这种情况,该列的最后一个块的部分到了下一列首部。
2、利用js实现
可以自定义列数、行间距、列间距,注意margin是用户在对父组件设置了margin的情况下需要填写的,没有设置可以不填。
/** * @description: * @param {*} vm : this * @param {*} parent : 瀑布流组件 * @param {*} arg:{cols : 设置列数, margin:父元素设置的margin, vgap:块之间的水平间隙,hgap : 块之间的竖直间隙} * @return {*} */
function waterFall(vm, parent, arg) {
const divVGap = arg.vgap || 20
const divHGap = arg.hgap || 20
const columns = arg.cols || 3; //默认3列
const margin = arg.margin || 0;
// 1 确定图片的宽度 - 滚动条宽度
const pageWidth = parent.clientWidth - divVGap * columns - margin * 2 - 8;
const itemWidth = parseInt(pageWidth / columns); //得到item的宽度
const list = Array.from(parent.children)
// 设置到item的宽度
list.forEach((item, i) => {
item.style.width = itemWidth + 'px'; //设置到item的宽度
})
vm.$nextTick(() => {
setTimeout(() => {
const arr = []; // 存储每列当前高度
list.forEach((item, i) => {
const height = item.clientHeight || item.offsetHeight;
if (i < columns) {
// 2 第一行按序布局
item.setAttribute("style", `top:0; left:${
(itemWidth) * i + divVGap * i}px; width:${
itemWidth}px`)
//将行高push到数组
arr.push(height);
} else {
// 其他行
// 3 找到数组中最小高度 和 它的索引
// 这种写法虽短,但没有下面的效率高
// const minHeight = Math.min(...arr);
// const index = arr.findIndex(item => item === minHeight);
let minHeight = arr[0];
let index = 0;
for (let j = 0; j < arr.length; j++) {
if (minHeight > arr[j]) {
minHeight = arr[j];
index = j;
}
}
// 4 设置下一行的第一个盒子位置 top值就是最小列的高度
// 1.8ms:耗时
// item.style.top = `${arr[index] + divHGap}px`
// item.style.left = `${(itemWidth) * index + divVGap * index}px`
// 0.3ms: 多个设置和合并成一个设置,性能更优,注意要加上width设置,此操作会把上面的width覆盖掉
item.setAttribute("style", `top:${
arr[index] + divHGap}px; left:${
(itemWidth) * index + divVGap * index}px; width:${
itemWidth}px`)
// 5 修改最小列的高度
// 最小列的高度 = 当前自己的高度 + 拼接过来的高度 + 竖直间隔
arr[index] = arr[index] + height + divHGap;
}
})
},100)
})
}
//clientWidth 处理兼容性
function getClient() {
return {
width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
}
}
export {
getClient, waterFall }
这里的vm.$nextTick 和 setTimeout
都是为了正确的获取高度,但是这个处理不准确,图片的加载不知道什么时候结束,所以这里可以使用图片的懒加载插件,在图片加载之后进行setTimeOut中间的操作。如vue-lazyload 等
在vue文件使用
这里监控onsize的变化可以跟随页面变化而调整瀑布流。
<template>
<div class="box" ref="box" id="box">
<div class="item" ref="item">
<img src="@/assets/image/not-exist@2x.png" alt="" />
</div>
<div class="item">
<img src="@/assets/image/1@2x.png" alt="" />
</div>
</div>
</template>
<script> import {
waterFall } from '@/assets/js/waterfall' export default {
mounted() {
waterFall(this, this.$refs.box, {
margin:40, vgap:40, hgap:30}) // 页面尺寸改变时实时触发 window.onresize = () => {
//重新定义瀑布流 waterFall(this, this.$refs.box,{
margin:40, vgap:40, hgap:30}) } }, } </script>
<style lang="scss" scoped> img{
width: 100%; height: 100%; } .box {
margin: 40px; width: 100%; position:relative; box-sizing: content-box; } .item {
position: absolute; border: 1px solid #5592e5; transition: all .3s; cursor: pointer; &:hover{
transform: scale(1.05,1.05); } } </style>
总结
这里只是简单的实现,后续还可以加上下拉加载等功能。
这里有些推荐瀑布流插件:https://www.cnblogs.com/ruruo/p/12938878.html,
vue-waterfall:这个要传入入瀑布流每项的宽高,这块可以通过上述代码的方式动态设置每个块的宽高。还可以自定义设置一些块位置变换时(页面缩小时)的过渡效果
vue-grid-layout : 提供自由拖拽的功能,官网上还有几个例子
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/20672.html