实战案例之瀑布流效果

前言

从服务器获取需要展示的数据(图片大小不一致,大中,中,小), 

每次从服务器获取三条数据,依次插入到三列中[每一列的宽度是一样的] 弊端:可能导致某一列特别的高,而某一列特别的矮

瀑布流:需求分析

  • 最终期望三列的高度差距应该是不大的才可以,
  • 最开始数据绑定完,不去加载真实的图片(提高页面首次渲染速度),等到数据绑定完成后,开始加载真实图片,(只加载可视窗口中的),随着页面的滚动在去加载出现在可视窗口中的,
  • 当滚动到页面底部,在从服务器获取50条数据,继续绑定到页面中实现下拉加载更多的效果

思路:第一次取出三条数据,直接按顺序,依次插入到三列中即可,第二次取出三条数据,最高的数据应该插入到最矮的列中

三条数据排序 小-->大,三列按高度排序 大-->小

下拉加载更多: 真实页面高度scrollHeight  卷去的高度scrollTop 一屏幕高度

一屏的高度+卷去的高度=真实页面高度,到底步了可以加载更多了

主体结构

三列             : 图片占位盒子          底部盒子

<body>
	<div class="container clearfix">
		<div class="column">
			<!-- <div class="card">
				<a href="#">
					<div class="lazyImageBox" style="height: 180px;">
						<img src="" alt="" data-image="images/1.jpg">
					</div>
					<p>泰勒·斯威夫特(Taylor Swift),1989年12月13日出生于美国宾州,美国歌手、演员。2006年出道,同年发行专辑《泰勒·斯威夫特》,该专辑获得美国唱片业协会的白金唱片认证</p>
				</a>
			</div> -->
		</div>
		<div class="column"></div>
		<div class="column"></div>
	</div>
	<div class="loadMore"></div>

	<!-- IMPORT JS -->
	<script src="js/index.js"></script>
</body>

css样式

每一列的宽度为240 注意;有10的padding值 图片大小实际为230

 height: xxx;  如果是需要进行图片延迟加载,在图片不显示的时候,我们要让盒子的高度等于图片的高度,这样才能把盒子撑开(服务器返回给我们的数据中,一定要包含图片的高度和宽度)

html,
body {
	background: #D6D7DB;
}

.container {
	box-sizing: border-box;
	margin: 20px auto;
	width: 760px;
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
}

.container .column {
	box-sizing: border-box;
	width: 240px;
}

.card {
	margin-bottom: 10px;
	padding: 5px;
	background: #FFF;
	box-shadow: 3px 3px 10px 0 #222;
}

.card a {
	display: block;
}

.card a .lazyImageBox {
	/* height: xxx;  如果是需要进行图片延迟加载,在图片不显示的时候,我们要让盒子的高度等于图片的高度,这样才能把盒子撑开(服务器返回给我们的数据中,一定要包含图片的高度和宽度) */
	background: url("../images/default.gif") no-repeat center center #F4F4F4;
	overflow: hidden;
}

.card a .lazyImageBox img {
	width: 100%;
	opacity: 0;
	transition: opacity .3s;
}

.card a p {
	margin-top: 5px;
	color: #000;
	font-size: 12px;
	line-height: 20px;
}

.loadMore {
	height: 100px;
}

JS

 false:同步获取数据「当前数据没有获取到之前,其余的事情是不进行处理的」,但是真实项目中都应该用异步获取,再基于promise/async/await等异步方案进行管理

 注意:基于VSCODE预览的项目的时候,不能再使用OPEN IN BROWSER这种模式了,因为这种模式是file://协议,不支持AJAX的请求;我们可以安装Live Server插件,基于Open With Live Server来预览,这样就可以了!!这种模式会再本地创建一个Web服务 http://127.0.0.1:5500/,基于这个服务就可以访问本地的数据了!!

扫盲

  •  JSON.stringify:把JSON格式的对象(对象)变为JSON格式字符串,
  • JSON.parse:把JSON格式的字符串变为JSON格式的对象(对象)

JSON数据格式:常用于客户端和服务器端的数据获取

相对于普通对象来讲,JSON格式的对象也是对象,只不过会把属性名都基于“”包起来而已

       //JSON格式对象
        let obj = {
            "name": "lisa",
            "age": 12
        };
        // JSON.stringify: 把JSON格式的对象(对象)变为JSON格式字符串
        console.log(JSON.stringify(obj));

        // JSON格式对象变为字符串后,称之为JSON格式的字符串
        let str = '{"name":"lisa","age":12}';
        // JSON.parse:把JSON格式的字符串变为JSON格式的对象(对象)
        console.log(JSON.parse(str));

数组排序

sort:b-a降序,a-b升序

        // 数组排序
        let arr = [10, 13, 24, 5];
        arr.sort((a, b) => {
            // b 当前循环这一项
            // a 当前这一项的后一项
            // 返回一个小于零的值,则a/b两项交换位置
            return b - a;
        });
        console.log(arr);

代码


// 节流函数
function throttle(func, wait = 500) {
    let timer = null,
        previous = 0;
    return function anonymous(...params) {
        let now = new Date(),
            remaining = wait - (now - previous);
        if (remaining <= 0) {
            clearTimeout(timer);
            timer = null;
            previous = now;
            func.call(this, ...params);
        } else if (!timer) {
            timer = setTimeout(() => {
                clearTimeout(timer);
                timer = null;
                previous = new Date();
                func.call(this, ...params);
            }, remaining);
        }
    };
}

let container = document.querySelector('.container'),
    columns = document.querySelectorAll('.column'),
    lazyImageBoxs = [];
//把类数组集合变为数组集合,使用数组方法
columns = Array.from(columns)

//基于ajax服务器获取数据
const queryData = () => {
    let data = [];
    let xhr = new XMLHttpRequest;
    xhr.open('GET', '../data.json', false);
    xhr.onreadystatechange = () => {
        if (xhr.readyState === 4 && xhr.status === 200) {
            //JSO格式字符串
            data = JSON.parse(xhr.response)
        }
    }
    xhr.send();
    return data;
};

//根据获取的数据完成页面的数据绑定
const bindHTML = data => {
    // 页面渲染的时候,图片按照宽230px渲染,服务器返回的图片大小:宽300*高433,所以为了保证图片不变形,我们需要把获取的数据中的图片宽高,按照真实的比例进行缩放  
    // A->渲染  B->服务器  A-W/A-H=B-W/B-H => A-H=A-W/(B-W/B-H)
    data = data.map(item => {
        let AW = 230,
            BW = item.width,
            BH = item.height,
            AH = AW / (BW / BH);
        item.width = AW;
        item.height = AH;
        return item;
    });

    // 每三个为一组进行数据遍历
    for (let i = 0; i < data.length; i += 3) {
        // group:当前循环获取的三条数据&把数据按照图片的高度排序 小->大
        let group = data.slice(i, i + 3);
        group.sort((a, b) => a.height - b.height);

        // 把当前页面中的三列按照高度进行排序 大->小
        columns.sort((a, b) => b.offsetHeight - a.offsetHeight);

        // 按照排好序的结果,分别把数据插入到指定的列中
        group.forEach((item, index) => {
            // 根据当前数据动态创建一个CARD
            let card = document.createElement('div');
            card.className = 'card';
            card.innerHTML = `<a href="${item.link}">
                <div class="lazyImageBox" style="height: ${item.height}px;">
                    <img src="" alt="" data-image="${item.pic}">
                </div>
                <p>${item.title}</p>
            </a>`;

            // 创建的CARD追加到指定的列中
            columns[index].appendChild(card);
            // 数据绑定完成后,才可以获取到所有图片延迟加载所在的盒子
            lazyImageBoxs = Array.from(container.querySelectorAll('.lazyImageBox'));
        });
    }
}

//单张图片的延迟加载
const lazyImgFunc = lazyImageBox => {
    let img = lazyImageBox.querySelector('img'),
        dataImage = img.getAttribute('data-image');
    img.onload = () => {
        img.style.opacity = 1;
    };
    img.src = dataImage;
    lazyImageBox.isLoad = true;
};
// 依次遍历每一个图片所在的盒子,所有符合条件的(出现在视口中的)都去做延迟加载
const lazyImageBoxsFunc = () => {
    let B = document.documentElement.clientHeight;
    lazyImageBoxs.forEach(lazyImageBox => {
        if (lazyImageBox.isLoad) return;
        let A = lazyImageBox.getBoundingClientRect().bottom;
        if (A <= B) {
            lazyImgFunc(lazyImageBox);
        }
    });
};
 开始加载页面:获取数据、数据绑定、等待1000MS(再或者页面滚动的时候)做图片延迟加载
let data = queryData();
bindHTML(data);
setTimeout(lazyImageBoxsFunc, 1000)
window.onscroll = throttle(() => {
    // 图片延迟加载
    lazyImageBoxsFunc();

    // 下拉加载更多数据
    let HTML = document.documentElement;
    if ((HTML.clientHeight + HTML.scrollTop + 100) >= HTML.scrollHeight) {
        let data = queryData();
        bindHTML(data);
    }
});

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值