vue+uniapp瀑布流布局多种实现方式

news2025/7/13 2:08:31

文章目录

  • 前言
  • 一、实现原理
  • 二、代码实现
    • 1.方式1(图片高度累加比较法)
    • 2.方式2(父元素高度比较法)
  • 三.uniapp实现
    • 代码实现
  • 四、多列实现
    • 代码实现


前言

瀑布流布局是网页设计常见的一种布局,一般用于图片多列展示。列宽固定,图片根据自身高度自适应交错排列。

在这里插入图片描述


一、实现原理

通过动态计算哪一列高度最低,就把图片放置该列下显示,直至所有图片分列完毕

计算哪一列高度最低具体实现过程又分2种方式:

方式1:通过计算每一列每张图片渲染后高度进行累加就是该列的高度,记录每列累加高度比较大小
方式2:直接通过图片父级元素高度(列div)来判断哪一列最低

区别:方式1无需等待图片真实渲染完成在比较高度,方式2需要等待图片真实渲染完成在获取高度

二、代码实现

以左右2列为例

<template>
  <div class="page">
    <!-- 左图片列表 -->
    <div class="left" ref="left">
      <img
        class="img"
        v-for="(item, index) in leftList"
        :key="index"
        :src="item"
      />
    </div>
    <!-- 右图片列表 -->
    <div class="right" ref="right">
      <img
        class="img"
        v-for="(item, index) in rightList"
        :key="index"
        :src="item"
      />
    </div>
  </div>
</template>
<style scoped>
.page {
  width: 100%;
  display: flex;
  align-items: flex-start;
  padding: 0 1%;
  box-sizing: border-box;
}
.left,
.right {
  margin: 0 auto;
  width: 48%;
}
.img {
  width: 100%;
  height: auto;
  margin-bottom: 10px;
}
</style>

1.方式1(图片高度累加比较法)

<script>
export default {
  data() {
    return {
      imgList: [
        "https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082",
        "https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
        "https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",
        "https://img1.baidu.com/it/u=3866290852,3566512524&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500",
        "https://img2.baidu.com/it/u=1114729443,1120710416&fm=253&fmt=auto&app=138&f=JPEG?w=667&h=500",
        "https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082",
        "https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
        "https://img2.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",
      ], //所有图片
      leftList: [], //左边列图片
      rightList: [], //右边列图片
      leftHeight: 0, //左边列高度
      rightHeight: 0, //右边列高度
      columnWidth: 0, //列宽度
    };
  },
  mounted() {
    this.$nextTick(() => {
      this.columnWidth = this.$refs.left.clientWidth;
      this.setWaterFallLayout();
    });
  },
  methods: {
    //方法1
    async setWaterFallLayout() {
      for (let item of this.imgList) {
        let img = new Image();
        img.src = item;
        try{
          let h = await this.getImgHeight(img);//图片渲染后高度
          if (this.leftHeight <= this.rightHeight) {//左边列比右边低,图片放入左边
            this.leftList.push(item);
            this.leftHeight += h;
          } else {//否则,图片放入右边
            this.rightList.push(item);
            this.rightHeight += h;
          }
        }catch(e){
          console.log(e)
        }
      }
    },
    //获取图片高度
    getImgHeight(img) {
      return new Promise((resolve,reject) => {
      //图片加载完成
        img.onload = () => {
          let h = (img.height / img.width) * this.columnWidth;//计算图片渲染后高度
          resolve(h);
        };
        //加载出错
        img.onerror=()=>{
          reject('error')
        }
      });
    },
  },
};
</script>

2.方式2(父元素高度比较法)

每次放入图片需要等待渲染后再重新计算父元素高度,关键代码 await this.$nextTick()

<script>
export default {
  data() {
    return {
      imgList: [
        "https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082",
        "https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
        "https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",
        "https://img1.baidu.com/it/u=3866290852,3566512524&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500",
        "https://img2.baidu.com/it/u=1114729443,1120710416&fm=253&fmt=auto&app=138&f=JPEG?w=667&h=500",
        "https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082",
        "https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
        "https://img2.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",
      ], //所有图片
      leftList: [], //左边列表图片
      rightList: [], //右边列表图片
    };
  },
  mounted() {
    this.$nextTick(() => {
      this.setWaterFallLayout2();
    });
  },
  methods: {
    //方法2
    async setWaterFallLayout2() {
      for (let item of this.imgList) {
        if (this.$refs.left.clientHeight <= this.$refs.right.clientHeight) {//左边列比右边低,图片放入左边
          this.leftList.push(item);
        } else {//否则图片放入右边
          this.rightList.push(item);
        }
        await this.$nextTick();//等待渲染完成后重新比较左右高度
      }
    },
  },
};
</script>

三.uniapp实现

由于uniapp获取元素高度和vue有所区别,造成实现瀑布流方式也需要调整。我们知道uniapp不能通过this.$ref.xx.clientHeight获取元素高度,而需要通过uni.createSelectorQuery().in(this).select(‘.xxxx’).boundingClientRect().exec()来获取,且经过实测当图片动态加入列后通过该api计算出父元素真实高度是不准确的,所以uniapp瀑布流布局实现方式只能通过方法1(也即图片高度累加法)进行实现,除了上面方法1通过img.onload来获取图片高度外,uniapp还提供uni.getImageInfo方法来更方便获取图片高度。

代码实现

<template>
	<view class="page">
		<view class="left" ref="left">
			<image class="image" v-for="(item,i) in leftList" :key="i" :src="item" mode="widthFix"></image>
		</view>
		<view class="right" ref="right">
			<image class="image" v-for="(item,i) in rightList" :key="i" :src="item" mode="widthFix"></image>
		</view>
	</view>
</template>
<style lang="scss">
	.page {
		width: 100%;
		display: flex;
		align-items: flex-start;
		padding: 0 1%;
		box-sizing: border-box;
	}

	.left,
	.right {
		margin: 0 auto;
		width: 48%;
	}

	.image {
		width: 100%;
		height: auto;
		margin-bottom: 10px;
	}
</style>

<script>
	export default {
		data() {
			return {
				imageList: [
					"https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082",
					"https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
					"https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",
					"https://img1.baidu.com/it/u=3866290852,3566512524&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500",
					"https://img2.baidu.com/it/u=1114729443,1120710416&fm=253&fmt=auto&app=138&f=JPEG?w=667&h=500",
					"https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082",
					"https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
					"https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",
				], //所有图片
				leftList: [], //左边列图片
				rightList: [], //右边列图片
				leftHeight: 0, //左边列高度
				rightHeight: 0, //右边列高度
				columnWidth: 0 //列宽度
			}
		},
		mounted() {
			this.$nextTick(() => {
				uni.createSelectorQuery().in(this).select('.left').boundingClientRect(res => {
					this.columnWidth = res.width
					//方法1
					this.setWaterFallLayout()
					//方法2
					// this.setWaterFallLayout2()
				}).exec()
			})
		},
		methods: {
			//方法1通过img.onload
			async setWaterFallLayout() {
				for (let item of this.imageList) {
					let img = new Image()
					img.src = item
					try {
						let h = await this.getImgHeight(img)
						if (this.leftHeight <= this.rightHeight) {
							this.leftList.push(item)
							this.leftHeight += h
						} else {
							this.rightList.push(item)
							this.rightHeight += h
						}
					} catch (e) {
						console.log(e)
					}

				}

			},
			//获取图片高度
			getImgHeight(img) {
				return new Promise((resolve, reject) => {
					img.onload = () => {
						let h = img.height / img.width * this.columnWidth
						resolve(h)
					}
					//加载出错
					img.onerror = () => {
						reject('error')
					}
				})
			},
			//方法2通过uni.getImageInfo
			async setWaterFallLayout2() {
				for (let item of this.imageList) {
					uni.getImageInfo({
						src: item,
						success: e => {
							if (this.leftHeight <= this.rightHeight) {
								this.leftList.push(item)
								this.leftHeight += e.height
							} else {
								this.rightList.push(item)
								this.rightHeight += e.height
							}

						}
					})
				}
			}

		},

	}
</script>

在这里插入图片描述


四、多列实现

多列实现和2列一样,动态生成每列图片数据和记录每列高度

在这里插入图片描述

代码实现

以最简单的父元素高度比较法(方式2)为例实现,图片高度累加比较法(方式1)自行类比实现

<template>
  <div class="page">
    <div
      class="column"
      ref="column"
      v-for="(item, index) in columnList"
      :key="index"
    >
      <img class="img" v-for="(n, i) in item" :key="i" :src="n" />
    </div>
  </div>
</template>
<style scoped>
.page {
  width: 100%;
  display: flex;
  align-items: flex-start;
  padding: 0 1%;
  box-sizing: border-box;
}

.column {
  flex: 1;
  padding: 0 10px;
  box-sizing: border-box;
  width: 0;
}

.img {
  width: 100%;
  height: auto;
  margin-bottom: 10px;
}
</style>
<script>
export default {
  data() {
    return {
      imgList: [
        "https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082",
					"https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
					"https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",
					"https://img1.baidu.com/it/u=3866290852,3566512524&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500",
					"https://img2.baidu.com/it/u=1114729443,1120710416&fm=253&fmt=auto&app=138&f=JPEG?w=667&h=500",
					"https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082",
					"https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
					"https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",
					"https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082",
					"https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
      ], //所有图片
      columnList: [], //分配后的每列图片
      columWidth: 0, //每列宽度
      columnCount: 5, //显示几列
    };
  },
  created() {
    //初始化数据
    for (let i = 0; i < this.columnCount; i++) {
      this.columnList.push([]);//生成每列图片数组
    }
  },
  mounted() {
    this.$nextTick(()=>{
      this.setWaterFallLayout();
    })
  },
  methods: {
   //瀑布布局
    async setWaterFallLayout() {
      for (let item of this.imgList) {
        let columnHeight = this.$refs.column.map((item) => item.clientHeight); //每列高度数组
        let min = Math.min(...columnHeight); //找出最小高度值
        let index = columnHeight.findIndex((item) => item === min); //找出最小高度列的索引
        this.columnList[index].push(item);//放入图片
        await this.$nextTick(); //等待渲染完成后重新比较高度
      }
    },
  },
};
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/406081.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3:状态管理-Store(Vuex,Pinia)

什么是状态管理 理论上来说&#xff0c;每一个 Vue 组件实例都已经在“管理”它自己的响应式状态了 它是一个独立的单元&#xff0c;由以下几个部分组成 状态&#xff1a;驱动整个应用的数据源&#xff1b;视图&#xff1a;对状态的一种声明式映射&#xff1b;交互&#xff1a…

写给20、21级学生的话

写给20、21级学生的话前言一、关于招聘变招生&#xff0c;你怎么看&#xff1f;二、对于即将实习/已经实习的学生&#xff0c;你有什么建议&#xff1f;1.学习方面2.提升方面三、思想成年真的很重要前言 最近&#xff0c;有一些同学遇到的实习问题&#xff0c;我统一回复下&…

Vue2通知提醒框(Notification)

项目相关依赖版本信息 可自定义设置以下属性&#xff1a; 自动关闭的延时时长&#xff08;duration&#xff09;&#xff0c;单位ms&#xff0c;默认4500ms消息从顶部弹出时&#xff0c;距离顶部的位置&#xff08;top&#xff09;&#xff0c;单位像素px&#xff0c;默认24p…

HTML常用快捷键都在这了 看完之后效率暴涨

是这么回事; 我今天上网页课的时候&#xff0c;发现好多同学在敲标签的时候敲得很慢&#xff0c;我再仔细一看&#xff0c;好家伙&#xff0c;他们的标签竟然都是一个一个的敲出来的&#xff01; 那效率能高吗&#xff1f; 这是当时让敲的代码&#xff0c;很简单&#xff0c;对…

css实现元素居中的5种方法

目录 1.最简单的方法 2.利用定位 3.定位配合css3位移 4.弹性盒模型 5.网格布局Grid 相信大家在面试的时候也会经常碰到css实现元素居中的方法&#xff0c;下面我介绍5中方法给大家&#xff0c;欢迎大家评论区交流 需求&#xff1a; 给定两个元素&#xff0c;这两个元素是…

vue项目设置打包后的静态文件访问路径

vue项目设置打包后的静态文件访问路径 **啰嗦一下&#xff1a;**相同域名下可能会存在两份相关或不相关的代码&#xff0c;需要通过切换文件夹路径进入不同项目时&#xff0c;需要在项目打包输出代码时设置静态文件的访问路径&#xff08;vue、react都要&#xff09;。这种方式…

架构之软件负载均衡LVS、Nginx、Haproxy、Keepalived

目前市面上最常见的负载均衡技术方案主要有三种&#xff1a; 基于DNS负载均衡&#xff0c; DNS负载均衡主要适用于的场景是多地集群的方式&#xff0c;也就是可能北京有一个数据中心&#xff0c;在其中部署了一整套的集群提供服务&#xff0c;在上海有一个数据中心&#xff0c…

图片的美白与美化

博主简介 博主是一名大二学生&#xff0c;主攻人工智能研究。感谢让我们在CSDN相遇&#xff0c;博主致力于在这里分享关于人工智能&#xff0c;c&#xff0c;Python&#xff0c;爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主&#xff0c;博主会继续更新的&#xff0c…

Error: Can‘t find Python executable “python“, you can set the PYTHON env variable.解决办法

&#x1f626;电脑磕坏了 最近把公司给的mac屏幕给磕坏了&#xff0c;换成自己的macbookpro&#xff0c;本来想用时间机器做个无缝衔接&#xff0c;结果发现不能用了&#xff0c;跟客服沟通被告知macos版本在11以上不支持时间机器系统迁移&#xff0c;只能使用迁移助理做数据备…

HTML实现简单的贪吃蛇小游戏(附完整源码)

基于HTML5技术的贪吃蛇小游戏的设计与实现 项目简介&#xff1a; 贪吃蛇作为我们儿时经典的游戏之一&#xff0c;它是一款单机而又好玩的小游戏。今天&#xff0c;就让我们用html5技术实现一个简单的贪吃蛇小游戏&#xff01; 项目核心技术&#xff1a; html5的canvasJS技术 …

Typora如何设置字体的颜色

作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; Typora如何设置字体的颜色 Typora没有直接设置字体颜色的功能&#xff0c;不能像word一样&#xff0c;选中字体直接设置想要的颜色。 …

uniapp使用高德地图

uniapp使用高德地图 1、项目前准备 1.1、首先你需要去申请一个属于自己的高德地图key&#xff0c;怎么申请暂不多说需要的去官网看 1.2、链接: 高德地图申请key直通车&#xff0c;点击前往。 有一个uniapp项目。 2、页面创建引入 新建一个uniapp的空白页 使用web-view 渲染…

Postman下载与安装操作步骤【超详细】

&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是超梦梦梦梦&#xff0c;很高兴认识大家~&#x1f357;关注➕点赞➕评论➕收藏 &#x1f604;&#x1f64f;博主水平有限&#xff0c;如有错误&#xff0c;欢迎各位大佬纠正 Postman下载与安装&#x1…

vue的指令和插值总结

文章目录一、安装vue二、Vue模板案例步骤三、基础模板&#xff08;记住&#xff09;四、vue的指令和插值1、{{}}&#xff1a;插值表达式的语法2、v-text&#xff1a;填充纯文本内容&#xff08;data中的值&#xff09;3、v-html&#xff1a;填充html&#xff08;data中的值&…

蓝桥杯刷题第九天

题目描述本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。素数就是不能再进行等分的整数。比如7&#xff0c;11。而 9 不是素数&#xff0c;因为它可以平分为 3 等份。一般认为最小的素数是2&#xff0c;接着是 3&#xff0c;5&…

el-upload 超详细-(附件,图片,多类型文件)玩转上传upload--new FormData()

代码&#xff08;我的项目代码&#xff1a;注解在下面&#xff09;代码复制直接用&#xff0c;可以实现所有文件上传&#xff0c;更改接口即可&#xff08;如需详细注解&#xff0c;学习&#xff0c;下面的详解完全够用&#xff0c;从0到学会这一片加官方文档就够了&#xff09…

Electron 分享(入门,安装,打包)

Electron Electron 是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架 安装 在使用 Electron 进行开发之前&#xff0c;需要安装Node.js&#xff0c;可以在终端输入以下命令输出了 Node.js 和 npm 的版本信息&#xff1a; node -v npm -v没有安装的话&#xff0c…

css 100vw、100vh出现滚动条怎么解决

要搞清楚这个问题首先要知道这两个单位&#xff08;vw、vh&#xff09;是什么意思。vw&#xff08;vh&#xff09;是相对于浏览器的视口宽度&#xff08;高度&#xff09;的&#xff0c;100vh等于浏览器的视口宽度&#xff0c;设置vw和vh会在视口发生变化时重新计算宽度和高度。…

【Vue实用功能】Vue实现文档在线预览功能,在线预览PDF、Word、Excel、ppt等office文件

文章目录[TOC](文章目录)方法一、 Luckysheet 预览方法二、 Office Web 查看器&#xff08;微软的开发接口&#xff09;方法三、 XDOC文档预览云服务(预览pdf、word、xls、ppt)方法一、 Luckysheet 预览 Luckysheet 是一个类似于 excel 的在线电子表格&#xff0c;功能强大、配…

超详细纯前端导出excel并完成各种样式的修改(xlsx-style)

超详细纯前端导出excel并完成各种样式的修改&#xff08;xlsx-style&#xff09; 一杠正在上传…重新上传取消 2020年12月08日 17:53 阅读 6247 一、前言 最近做的项目涉及到了excel的导出&#xff0c;在这块真的花了很多的时间&#xff0c;起初需求是不需要样式层面的修改…