


Take you step by step to use Vue to implement a picture horizontal waterfall flow plug-in
How to use Vue to implement a picture horizontal waterfall flow plug-in? Here I would like to share with you some knowledge I have summarized on the Internet, I hope it will be helpful to you.
1. Source of demand
I encountered a requirement today, which needs to be displayed horizontally on the page Loading some pictures using the waterfall flow method suddenly reminded me of an article I wrote a long time ago "Two Ways to Implement Horizontal Waterfall Flow Layout in JS"
But there is one Problem, this requirement is for the Vue project, so there is no way. Here I will share with you my development process. The main body of the project is developed using the CRMEB back-end framework that I have been learning before. The UI uses iView-UI. The rest of the scenarios are the same as Other Vue projects are the same. [Related recommendations: vuejs video tutorial]
2. Logical assumption
If it is not the vue environment, our logic For
1.获取所有的p元素 2.获取盒子的宽度,宽度都是相同,高度不同 3.在浮动布局中每一行的盒子个数不固定,是根据屏幕宽度和盒子宽度决定 4.获取屏幕宽度 5.求出列数,屏幕宽度 / 盒子宽度 取整 6.瀑布流最关键的是第二行的盒子的排布方式,通过获取第一行盒子中最矮的一个的下标,绝对定位,top是最矮盒子的高度,left是最矮盒子的下标 * 盒子的宽度 7.循环遍历所有的盒子,通过列数找到第一行所有的盒子,将第一行盒子的高度放入数组,再取出数组中最小的一个的下标,就是第6步思路的第一行盒子中最矮盒子的下标。 8.循环继续,第二行第一个盒子,通过绝对定位,放进页面。 9.关键,需要将数组中最小的值加上放进的盒子的高度 10.继续循环,遍历所有 11.如果想要加载更多,需要判断最后一个盒子的高度和页面滚动的距离,再将数据通过创建元素,追加进页面,再通过瀑布流布局展示
But if it is a Vue project, we can boil the logic down to the following steps
1.获取屏幕宽度 2..获取盒子的宽度,宽度都是相同,高度不同 3.在浮动布局中每一行的盒子个数不固定,是根据屏幕宽度和盒子宽度决定 4.求出列数,屏幕宽度 / 盒子宽度 取整 5.瀑布流最关键的是第二行的盒子的排布方式,通过获取第一行盒子中最矮的一个的下标,绝对定位,top是最矮盒子的高度,left是最矮盒子的下标 * 盒子的宽度 6.继续循环,遍历所有 7.如果想要加载更多,需要判断最后一个盒子的高度和页面滚动的距离,再将数据通过创建元素,追加进页面,再通过瀑布流布局展示
3. Final effect picture
##4. Code analysis
Let’s take a look at my html part first
<template> <div class="tab-container" id="tabContainer"> <div class="tab-item" v-for="(item, index) in pbList" :key="index"> <img src="/static/imghwm/default1.png" data-src="item.url" class="lazy" : / alt="Take you step by step to use Vue to implement a picture horizontal waterfall flow plug-in" > </div> </div> </template> <style scoped> * { margin: 0; padding: 0; } /* 最外层大盒子 */ .tab-container { padding-top: 20px; position: relative; } /* 每个小盒子 */ .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; /* 元素不能中断显示 */ break-inside: avoid; text-align: center; } .tab-container .tab-item img { width: 100%; height: auto; display: block; } </style>
Core js part
<script> 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; } } }, }, }; </script>
I would like to remind everyone here that when using the plug-in, we need to use this.$nextTick() to initialize the page, because the premise of the method's success is to wait for the page Acquisition and calculation can only be performed after the initial loading is completed
The overall plug-in code is:
<script>
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;
}
}
},
},
};
</script>

5. Outer layer usage and lazy loading
When using this plug-in, there are two problems, that is because the inner layer is position: absolute; positioned, it will not open the outer p, which will cause the outer layer to The box model is not easy to lay out, and the page is lazy to load when it is pulled down. So what should we do?
Here I give my processing method
<template>
<div>
<div class="list-box" @scroll="scrollFun">
<compList :pbList="pbList" ref="compList"></compList>
</div>
</div>
</template>
<script>
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)
}
}
};
</script>
<style scoped>
.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;
}
</style>
The core code of the drop-down is:
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) }
The global loading event of iView-UI is used here. If you want to use other UI frameworks, you can also modify it yourself
Here, all the ideas are over
(Learning video sharing:web front-end development, Basic programming video )
The above is the detailed content of Take you step by step to use Vue to implement a picture horizontal waterfall flow plug-in. For more information, please follow other related articles on the PHP Chinese website!

Vue.js and React each have their own advantages and disadvantages. When choosing, you need to comprehensively consider team skills, project size and performance requirements. 1) Vue.js is suitable for fast development and small projects, with a low learning curve, but deep nested objects can cause performance problems. 2) React is suitable for large and complex applications, with a rich ecosystem, but frequent updates may lead to performance bottlenecks.

Vue.js is suitable for small to medium-sized projects, while React is suitable for large projects and complex application scenarios. 1) Vue.js is easy to use and is suitable for rapid prototyping and small applications. 2) React has more advantages in handling complex state management and performance optimization, and is suitable for large projects.

Vue.js and React each have their own advantages: Vue.js is suitable for small applications and rapid development, while React is suitable for large applications and complex state management. 1.Vue.js realizes automatic update through a responsive system, suitable for small applications. 2.React uses virtual DOM and diff algorithms, which are suitable for large and complex applications. When selecting a framework, you need to consider project requirements and team technology stack.

Vue.js and React each have their own advantages, and the choice should be based on project requirements and team technology stack. 1. Vue.js is community-friendly, providing rich learning resources, and the ecosystem includes official tools such as VueRouter, which are supported by the official team and the community. 2. The React community is biased towards enterprise applications, with a strong ecosystem, and supports provided by Facebook and its community, and has frequent updates.

Netflix uses React to enhance user experience. 1) React's componentized features help Netflix split complex UI into manageable modules. 2) Virtual DOM optimizes UI updates and improves performance. 3) Combining Redux and GraphQL, Netflix efficiently manages application status and data flow.

Vue.js is a front-end framework, and the back-end framework is used to handle server-side logic. 1) Vue.js focuses on building user interfaces and simplifies development through componentized and responsive data binding. 2) Back-end frameworks such as Express and Django handle HTTP requests, database operations and business logic, and run on the server.

Vue.js is closely integrated with the front-end technology stack to improve development efficiency and user experience. 1) Construction tools: Integrate with Webpack and Rollup to achieve modular development. 2) State management: Integrate with Vuex to manage complex application status. 3) Routing: Integrate with VueRouter to realize single-page application routing. 4) CSS preprocessor: supports Sass and Less to improve style development efficiency.

Netflix chose React to build its user interface because React's component design and virtual DOM mechanism can efficiently handle complex interfaces and frequent updates. 1) Component-based design allows Netflix to break down the interface into manageable widgets, improving development efficiency and code maintainability. 2) The virtual DOM mechanism ensures the smoothness and high performance of the Netflix user interface by minimizing DOM operations.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

DVWA
Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

VSCode Windows 64-bit Download
A free and powerful IDE editor launched by Microsoft

SublimeText3 Chinese version
Chinese version, very easy to use

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),
