VUE + 瀑布流 + 懒加载,一片文章足矣

1. 什么是瀑布流

瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。即多行等宽元素排列,后面的元素依次添加到其后,等宽不等高,根据图片原比例缩放直至宽度达到我们的要求,依次按照规则放入指定位置。

2. 为什么使用瀑布流

瀑布流布局在我们现在的前端页面中经常会用的到,它可以有效的降低页面的复杂度,节省很多的空间,对于整个页面不需要太多的操作,只需要下拉就可以浏览用户需要看到的数据;并且,瀑布流可以提供很好的用户体验,通过结合下拉刷新,上拉加载进行数据的懒加载等操作,对于用户的体验感来说是接近于满分的!

3. 瀑布流的特点

其实瀑布流的特点就是参差不齐的排列方式,以及流式布局的扩展性,可以通过界面展示给用户多条数据,并且让用户可以有向下浏览的冲动。

实现瀑布流的方式有很多种,本期主要讲解js实现瀑布流

首先创建一个主页面,里面可以进行数据交互,这里我用setTimeout表示每次请求的数据,new IntersectionObserver是dom出现在可视窗口就会执行,用来做懒加载

<template>
	<div class="Falls_box">
		<div class="header title">瀑布流</div>
		<Falls ref="falls" @loadend="loading = false"></Falls>
		<div class="loading">
			<span v-show="loading">正在加载...</span>
			<span v-show="!loading && !finish" ref="loadmore"
				>点击加载更多</span
			>
			<span v-show="!loading && finish">没有更多数据</span>
		</div>
	</div>
</template>

<script>
	import Falls from "./Falls.vue";
	export default {
		name: "Falls_box",
		data() {
			return {
				loading: false,
				finish: false,
				page: 0,
				imgList:[
					{
						id:1,
						url:'https://gips3.baidu.com/it/u=871100818,1642628489&fm=3042&app=3042&f=JPEG&wm=1,huayi,0,0,13,9&wmo=0,0',
					},{
						id:2,
						url:'https://gips2.baidu.com/it/u=2514616750,584354736&fm=3042&app=3042&f=JPEG&wm=1,huayi,0,0,13,9&wmo=0,0',
					},{
						id:3,
						url:'https://gips0.baidu.com/it/u=3622901982,1201032983&fm=3042&app=3042&f=JPEG&wm=1,huayi,0,0,13,9&wmo=0,0',
					},{
						id:4,
						url:'https://gips2.baidu.com/it/u=783874742,472799755&fm=3042&app=3042&f=JPEG&wm=1,huayi,0,0,13,9&wmo=0,0',
					},{
						id:5,
						url:'https://gips0.baidu.com/it/u=1504464430,772353756&fm=3042&app=3042&f=JPEG&wm=1,huayi,0,0,13,9&wmo=0,0',
					},{
						id:6,
						url:'https://gips1.baidu.com/it/u=120482431,301978690&fm=3042&app=3042&f=JPEG&wm=1,huayi,0,0,13,9&wmo=0,0',
					}
				]
			};
		},
		mounted() {
			new IntersectionObserver(
				(entries, observer) => {
					// 如果不是相交,则直接返回
					if (!entries[0].intersectionRatio) return;
					this.onLoadMore();
				},
				{ root: document.body }
			).observe(this.$refs.loadmore);
		},
		// 挂载方法
		methods: {
			onLoadMore() {
				if (this.finish || this.loading) return;
				this.loading = true;
				var sendData = {
					page: ++this.page,
				};
				setTimeout(() => {
					if(true){//true为继续加载
						this.$refs.falls.push(list);
					}else{
						this.loading = false;
						this.finish = true;
					}
				}, 1000);
			},
		},
		// 计算属性
		computed: {},
		components: { Falls },
	};
</script>

<style lang='less' scoped>
	.Falls_box {
		> .loading {
			text-align: center;
			margin: 10px 0;
			font-size: 14px;
			color: rgb(89, 89, 255);
		}
	}
</style>

看到我们在setTimeout中把数据添加到子页面

子页面对每次push进来的图片进行处理瀑布排列,这里的处理流程就是,首先创建一个数组poss用来表示每列的当前高度,然后对这个图片并且设置一个宽度,根据这个宽度拿到图片高度,假如当前屏宽除设置的瀑布流列宽有三列 poss的初始状态就为[0,0,0],

接下会使用循环对poss遍历找出三位数字中最低值的下标,这个下表就是我们接下来要添加图片的位置

<template>
	<div class="Falls">
		<img
			v-for="v in list"
			:key="v.id"
			:src="v.url"
			:style="{
				width: v.style.width + 'px',
				height: v.style.height + 'px',
				top: v.style.top + 'px',
				left: v.style.left + 'px',
			}"
		/>
	</div>
</template>

<script>
	export default {
		name: "Falls",
		data() {
			return {
				list: [],
				wait_list: [],
				width: 300,
				num_x: 1,
				gap_x: 0,
				gap_y: 0,
				poss: [],
				loading: false,
			};
		},
		created() {},
		mounted() {
			this.resize();
			window.addEventListener("resize", this.resize);
		},
		beforeDestroy() {
			this.wait_list = [];
			window.removeEventListener("resize", this.resize);
		},
		// 挂载方法
		methods: {
			push(arr) {
				this.wait_list = this.wait_list.concat(arr);
				if (!this.loading) {
					this.loading = true;
					this.loadImg();
				}
			},
			loadImg() {
				if (this.wait_list.length <= 0) {
					this.loading = false;
					this.$emit("loadend");
					return;
				}
				let url = this.wait_list[0].url;
				let id = this.wait_list[0].id;
				let img = document.createElement("img");
				img.src = url;
				img.style.width = this.width + "px";
				img.style.position = "absolute";
				img.style.top = "-99999px";
				document.body.appendChild(img);
				img.addEventListener("load", () => {
					var idx = 0;
					var pos_num = this.poss[idx];
					for (var i = 1; i < this.poss.length; i++) {
						if (pos_num > this.poss[i]) {
							idx = i;
							pos_num = this.poss[i];
						}
					}
					let width = img.offsetWidth;
					let height = img.offsetHeight;
					let top = this.poss[idx] + this.gap_y;
					let left = (idx + 1) * this.gap_x + idx * width;
					this.poss[idx] = top + height;
					let obj = {
						id,
						url,
						style: { width, height, top, left },
					};
					this.list.push(obj);
					img.remove();
					this.wait_list.splice(0, 1);
					this.$el.style.height =
						Math.max(...this.poss) + this.gap_y + "px";
					if (this.wait_list.length <= 0) {
						this.loading = false;
						this.$emit("loadend");
					} else {
						this.loadImg();
					}
				});
			},
			resize() {
				var t_width = this.$el.offsetWidth;
				var width = this.width;
				var num_x = parseInt(t_width / (width + 20));
				if (num_x < 1) num_x = 1;
				var remain = t_width - width * num_x;
				var gap_x = remain / (num_x + 1);
				this.gap_x = gap_x;
				this.gap_y = gap_x > 30 ? 30 : gap_x;
				this.num_x = num_x;
				var poss = [];
				for (var i = 0; i < num_x; i++) poss.push(0);
				this.poss = poss;
				this.reset();
			},
			reset() {
				for (let i = 0; i < this.list.length; i++) {
					let width = this.list[i].style.width;
					let height = this.list[i].style.height;
					var idx = 0;
					var pos_num = this.poss[idx];
					for (var j = 1; j < this.poss.length; j++) {
						if (pos_num > this.poss[j]) {
							idx = j;
							pos_num = this.poss[j];
						}
					}
					let top = this.poss[idx] + this.gap_y;
					let left = (idx + 1) * this.gap_x + idx * width;
					this.poss[idx] = top + height;
					this.list[i].style = { width, height, top, left };
				}
				this.$el.style.height = Math.max(...this.poss) + this.gap_y + "px";
			},
		},
		// 计算属性
		computed: {},
		components: {},
	};
</script>

<style lang='less' scoped>
	.Falls {
		width: 100%;
		height: auto;
		position: relative;
		> img {
			position: absolute;
			transition: all 0.15s;
		}
	}
</style>

resize()方法则是监听屏幕宽度的变化进行修改边距和poss的列数具体效果如图

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值