分享一个Vue实现图片水平瀑布流的插件

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

分享一个Vue实现图片水平瀑布流的插件

一.需求来源

今天碰到了一个需求,需要在页面里,用水平瀑布流的方式,将一些图片进行加载,这让我突然想起我很久以前写的一篇文章《JS两种方式实现水平瀑布流布局》

但是有个问题,这个需求是Vue项目的,那没办法,这里给大家分享下我的开发过程,项目主体用的是之前在学习的CRMEB的后端框架来开发,UI使用iView-UI,其余的场景与其他的vue项目一致

二.逻辑设想

如果不是vue环境,我们的逻辑为

html;gutter:true; 1.获取所有的div元素 2.获取盒子的宽度,宽度都是相同,高度不同 3.在浮动布局中每一行的盒子个数不固定,是根据屏幕宽度和盒子宽度决定 4.获取屏幕宽度 5.求出列数,屏幕宽度 / 盒子宽度 取整 6.瀑布流最关键的是第二行的盒子的排布方式,通过获取第一行盒子中最矮的一个的下标,绝对定位,top是最矮盒子的高度,left是最矮盒子的下标 * 盒子的宽度 7.循环遍历所有的盒子,通过列数找到第一行所有的盒子,将第一行盒子的高度放入数组,再取出数组中最小的一个的下标,就是第6步思路的第一行盒子中最矮盒子的下标。 8.循环继续,第二行第一个盒子,通过绝对定位,放进页面。 9.关键,需要将数组中最小的值加上放进的盒子的高度 10.继续循环,遍历所有 11.如果想要加载更多,需要判断最后一个盒子的高度和页面滚动的距离,再将数据通过创建元素,追加进页面,再通过瀑布流布局展示</p> <pre><code> ### 但如果是Vue项目,我们可以把逻辑归结为以下几步 ;gutter:true;
1.获取屏幕宽度
2..获取盒子的宽度,宽度都是相同,高度不同
3.在浮动布局中每一行的盒子个数不固定,是根据屏幕宽度和盒子宽度决定
4.求出列数,屏幕宽度 / 盒子宽度 取整
5.瀑布流最关键的是第二行的盒子的排布方式,通过获取第一行盒子中最矮的一个的下标,绝对定位,top是最矮盒子的高度,left是最矮盒子的下标 * 盒子的宽度
6.继续循环,遍历所有
7.如果想要加载更多,需要判断最后一个盒子的高度和页面滚动的距离,再将数据通过创建元素,追加进页面,再通过瀑布流布局展示

三.最终效果图片

四.代码分析

先看下我的html部分

html;gutter:true; * { margin: 0; padding: 0; } /<em> 最外层大盒子 </em>/ .tab-container { padding-top: 20px; position: relative; } /<em> 每个小盒子 </em>/ .tab-container .tab-item { position: absolute; height: auto; border: 1px solid #ccc; box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04); background: white; /<em> 元素不能中断显示 </em>/ break-inside: avoid; text-align: center; } .tab-container .tab-item img { width: 100%; height: auto; display: block; }</p> <pre><code> ### 核心js部分 ;gutter:true;
export default {
name:’compList’,
props:{
pbList:{
type:Array,
default:()=>{return []}
}
},
data() {
return {
};
},
mounted() {
this.$nextTick(()=>{
this.waterFall("#tabContainer", ".tab-item"); //实现瀑布流
})
},
methods: {
waterFall(
wrapIdName,
contentIdName,
columns = 5,
columnGap = 20,
rowGap = 20
) {
// 获得内容可用宽度(去除滚动条宽度)
const wrapContentWidth =
document.querySelector(wrapIdName).offsetWidth;

// 间隔空白区域
const whiteArea = (columns – 1) * columnGap;

// 得到每列宽度(也即每项内容宽度)
const contentWidth = parseInt((wrapContentWidth – whiteArea) / columns);

// 得到内容项集合
const contentList = document.querySelectorAll(contentIdName);

// 成行内容项高度集合
const lineConentHeightList = [];

for (let i = 0; i < contentList.length; i++) {
// 动态设置内容项宽度
contentList[i].style.width = contentWidth + "px";

// 获取内容项高度
const height = contentList[i].clientHeight;

if (i < columns) {
// 第一行按序布局
contentList[i].style.top = "0px";
contentList[i].style.left = contentWidth * i + columnGap * i + "px";

// 将行高push到数组
lineConentHeightList.push(height);
} else {
// 其他行
// 获取数组最小的高度 和 对应索引
let minHeight = Math.min(…lineConentHeightList);
let index = lineConentHeightList.findIndex(
(listH) => listH === minHeight
);

contentList[i].style.top = minHeight + rowGap +"px";
contentList[i].style.left = (contentWidth + columnGap) * index + "px";

// 修改最小列的高度 最小列的高度 = 当前自己的高度 + 拼接过来的高度 + 行间距
lineConentHeightList[index] += height + rowGap;
}
}
},
},
};

这里要给大家提个醒,在当插件使用的时候,我们需要用 this.$nextTick()来进行页面初始化,因为方法成功的前提是要等页面初始化加载完毕后才能进行获取和计算

总体插件代码为:

html;gutter:true; export default { name:'compList', props:{ pbList:{ type:Array, default:()=>{return []} } }, data() { return { }; }, mounted() { this.$nextTick(()=>{ this.waterFall("#tabContainer", ".tab-item"); //实现瀑布流 }) }, methods: { waterFall( wrapIdName, contentIdName, columns = 5, columnGap = 20, rowGap = 20 ) { // 获得内容可用宽度(去除滚动条宽度) const wrapContentWidth = document.querySelector(wrapIdName).offsetWidth;</p> <pre><code> // 间隔空白区域 const whiteArea = (columns - 1) * columnGap; // 得到每列宽度(也即每项内容宽度) const contentWidth = parseInt((wrapContentWidth - whiteArea) / columns); // 得到内容项集合 const contentList = document.querySelectorAll(contentIdName); // 成行内容项高度集合 const lineConentHeightList = []; for (let i = 0; i < contentList.length; i++) { // 动态设置内容项宽度 contentList[i].style.width = contentWidth + "px"; // 获取内容项高度 const height = contentList[i].clientHeight; if (i < columns) { // 第一行按序布局 contentList[i].style.top = "0px"; contentList[i].style.left = contentWidth * i + columnGap * i + "px"; // 将行高push到数组 lineConentHeightList.push(height); } else { // 其他行 // 获取数组最小的高度 和 对应索引 let minHeight = Math.min(...lineConentHeightList); let index = lineConentHeightList.findIndex( (listH) => listH === minHeight ); contentList[i].style.top = minHeight + rowGap +"px"; contentList[i].style.left = (contentWidth + columnGap) * index + "px"; // 修改最小列的高度 最小列的高度 = 当前自己的高度 + 拼接过来的高度 + 行间距 lineConentHeightList[index] += height + rowGap; } } }, </code></pre> <p>}, };</p> <ul> <li>{ margin: 0; padding: 0; } /<em> 最外层大盒子 </em>/ .tab-container { padding-top: 20px; position: relative; } /<em> 每个小盒子 </em>/ .tab-container .tab-item { position: absolute; height: auto; border: 1px solid #ccc; box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04); background: white; /<em> 元素不能中断显示 </em>/ break-inside: avoid; text-align: center; } .tab-container .tab-item img { width: 100%; height: auto; display: block; }</li> </ul> <pre><code> ## 五.外层使用和懒加载 ### 在使用这个插件的时候,有两个问题,就是因为内层是 position: absolute;定位,不会撑开外部的div,会导致外层盒模型不好布局,还有就是页面下拉懒加载,那要怎么办呢? ### 这里我给出我的处理方法 ![分享一个Vue实现图片水平瀑布流的插件](https://johngo-pic.oss-cn-beijing.aliyuncs.com/articles/20230809/2149129-20220930145352080-1441381667.png) ### 整体代码如下: ;gutter:true;
import compList from "@/pages/test/components/compList";
export default {
name:’testList’,
components:{
compList
},
data() {
return {
//瀑布流数据
pbList: [
{
url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fphoto%2Fm%2Fpublic%2Fp2650049201.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664935370&t=d4bf3e4d352c277a1bdebfcc8fda959f",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
},
{
url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fphoto%2Fm%2Fpublic%2Fp2650049201.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664935370&t=d4bf3e4d352c277a1bdebfcc8fda959f",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
},
{
url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fphoto%2Fm%2Fpublic%2Fp2650049201.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664935370&t=d4bf3e4d352c277a1bdebfcc8fda959f",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
},
{
url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fphoto%2Fm%2Fpublic%2Fp2650049201.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664935370&t=d4bf3e4d352c277a1bdebfcc8fda959f",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
},
{
url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fphoto%2Fm%2Fpublic%2Fp2650049201.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664935370&t=d4bf3e4d352c277a1bdebfcc8fda959f",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
}
],
addList:[
{
url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fphoto%2Fm%2Fpublic%2Fp2650049201.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664935370&t=d4bf3e4d352c277a1bdebfcc8fda959f",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
},
{
url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fphoto%2Fm%2Fpublic%2Fp2650049201.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664935370&t=d4bf3e4d352c277a1bdebfcc8fda959f",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
},
{
url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fphoto%2Fm%2Fpublic%2Fp2650049201.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664935370&t=d4bf3e4d352c277a1bdebfcc8fda959f",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
},
{
url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fphoto%2Fm%2Fpublic%2Fp2650049201.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664935370&t=d4bf3e4d352c277a1bdebfcc8fda959f",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
},
{
url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fphoto%2Fm%2Fpublic%2Fp2650049201.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664935370&t=d4bf3e4d352c277a1bdebfcc8fda959f",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
},
{
url: "https://img1.baidu.com/it/u=2911909188,130959360&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=641",
}
],
bottomMain:true
};
},
methods:{
scrollFun(e) {
const offsetHeight= e.target.offsetHeight
const scrollHeight= e.target.scrollHeight
const scrollTop= e.target.scrollTop
if((scrollHeight – (offsetHeight+scrollTop)) < 10){
if(this.bottomMain){
this.bottomMain = false
this.addListDataFun()
}
}
},
addListDataFun(){
this.$Spin.show({
render: (h) => {
return h(‘div’, [
h(‘Icon’, {
‘class’: ‘demo-spin-icon-load’,
props: {
type: ‘ios-loading’,
size: 18
}
}),
h(‘div’, ‘数据更新中…’)
])
}
});
setTimeout(() => {
this.pbList = this.pbList.concat(this.addList)
this.bottomMain = true
this.$nextTick(()=>{
this.$refs.compList.waterFall("#tabContainer", ".tab-item")
this.$Spin.hide()
})
},1000)
}
}
};

.list-box{
position: relative;
width: 100%;
height: calc(100vh – 240px);
background: white;
padding: 20px 30px 20px 20px;
margin-top: 20px;
box-sizing: border-box;
overflow: auto;
}

下拉的核心代码为:

html;gutter:true;
scrollFun(e) {
const offsetHeight= e.target.offsetHeight
const scrollHeight= e.target.scrollHeight
const scrollTop= e.target.scrollTop
if((scrollHeight - (offsetHeight+scrollTop)) < 10){
if(this.bottomMain){
this.bottomMain = false
this.addListDataFun()
}
}
},
addListDataFun(){
this.$Spin.show({
render: (h) => {
return h('div', [
h('Icon', {
'class': 'demo-spin-icon-load',
props: {
type: 'ios-loading',
size: 18
}
}),
h('div', '数据更新中...')
])
}
});
setTimeout(() => {
this.pbList = this.pbList.concat(this.addList)
this.bottomMain = true
this.$nextTick(()=>{
this.$refs.compList.waterFall("#tabContainer", ".tab-item")
this.$Spin.hide()
})
},1000)
}

这里使用的是iView-UI的全局加载事件,如果你要用其他的UI框架,也可以自行修改

到这里,所有的思路就结束了

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

分享一个Vue实现图片水平瀑布流的插件

Original: https://www.cnblogs.com/smileZAZ/p/16744941.html
Author: 林恒
Title: 分享一个Vue实现图片水平瀑布流的插件

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/801637/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • numpy保存加载数据(字典数据)

    在使用numpy保存和加载数据的时候分别遇到了allow_pickle=False报错和字典数据加载后如何使用的问题,总结梳理如下。 numpy的保存和加载分别是以下两个函数: n…

    Python 2023年8月29日
    042
  • 2022需求最大的8种编程语言排名

    DevJobsScanner分析了过去16个月(从2021 10月到2023年3月)超过1200万开发人员的工作需求,并选择了明确需要编程语言的工作机会,获得了2022年最流行的八…

    Python 2023年10月7日
    036
  • OpenCV的cv2.minAreaRect解析

    在这个文章中,我们将学习如何在感兴趣区域周围画最小面积矩形框。 1.最小面积矩形框 下图显示了两个矩形框,绿色的是普通矩形框,红色的是最小面积矩形框。可以发现,红色的是旋转矩形。O…

    Python 2023年8月1日
    051
  • ElasticSearch系列——查询、Python使用、Django/Flask集成、集群搭建,数据分片、位置坐标实现附近的人搜索

    啊哦~你想找的内容离你而去了哦 内容不存在,可能为如下原因导致: ① 内容还在审核中 ② 内容以前存在,但是由于不符合新 的规定而被删除 ③ 内容地址错误 ④ 作者删除了内容。 可…

    Python 2023年8月13日
    045
  • Python – 实现渐变色的RGB计算

    一、解决了什么问题: 求得两个颜色之间颜色渐变的RGB。 二、公式: Gradient = A + (B-A) / Step * N编程时为了提高效率避免浮点运算,往往把除法放在最…

    Python 2023年8月30日
    042
  • django 报错 ‘set’ object is not reversible 解决

    这个问题在网上随便一搜就有解决办法,说是把urls.py里面的urlpatterns = 这部分的{}改成[]就可以了,想想也对,毕竟里面是个list也不是个dict 先说下我的p…

    Python 2023年10月31日
    040
  • 【赵渝强老师】Redis的慢查询日志

    Redis慢查询日志帮助开发和运维人员定位系统存在的慢操作。慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(慢查询ID,发生时间戳,…

    Python 2023年6月3日
    068
  • 爬虫系列:穿越网页表单与登录窗口进行采集(二)

    上一期我们讲解了 Python Requests 库、提交一个基本表单、HTML 相关控件等内容。 本篇文章我们接着上一期文章介绍通过 Python Requests 提交文件和图…

    Python 2023年6月10日
    0114
  • QSAN: A Quantum-probability based Signed Attention Network for Explainable False Information Detection-CIKM20

    一、摘要 在社交媒体上的虚假信息检测具有挑战性,因为它通常需要烦冗的证据收集,但又缺乏可用的比较信息。从用户评论中挖掘出的线索作为群体智慧,可能对这项任务有相当大的好处。 然而,考…

    Python 2023年10月28日
    040
  • 『51单片机』串口通信配置

    🚩 write in front 🚩 🔎大家好,我是謓泽,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎🏅2021年度博客之星物联网与嵌入式开发TOP5~2021博客之…

    Python 2023年11月9日
    062
  • Flask项目使用MVC思想进行重构

    目录 前言 MVC简介 项目架构图: 系统工作原理 服务层级统一包装结果 事务控制原理和代码 前言 最近Boss有需求说要重构后端的web项目,之前是用flask+celery+m…

    Python 2023年8月15日
    047
  • Pytest中断言assert的使用方法

    在Python语言中表示False的数值即各个数据类型的空值,如整数的0,字符串的空字符串,None值,空列表、空字典、空集合、空元组,布尔类型的False等,这里需要注意的是一个…

    Python 2023年9月10日
    048
  • Django 内设置读写分离

    1.启动Mysql一主一从服务Mysql的一主多从下,只有主库才能进行读写,从库只能读不能写2.在setting.py,中首先配置多个数据库 DATABASES = { #&amp…

    Python 2023年6月3日
    042
  • pandas读写Excel指南 解决中文乱码

    如果在使用 取 SQL Server 数据库并将数据 文件时出现 码问题,可以考虑在 时设置编码格式。 以下是示例代码: `python import as pd import p…

    Python 2023年8月21日
    040
  • flask-17 flask-sqlalchemy查询

    查询记录 那么我们怎么从数据库中查询数据?为此,Flask-SQLAlchemy 在您的 Model 类上提供了 query 属性。当您访问它时,您会得到一个新的所有记录的查询对象…

    Python 2023年8月10日
    045
  • 手部21个关键点检测+手势识别-[MediaPipe]

    MediaPipe 是一款由 Google Research 开发并开源的多媒体机器学习模型应用框架,可以直接调用其API完成目标检测、人脸检测以及关键点检测等。本篇文章介绍其手部…

    Python 2023年10月10日
    038
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球