需求文档:
瀑布流:宽度相同的多列不规则排布。
这些列宽度相同,列中的每一块宽度相同,高度不同。但是最终这些列的高度不能相差太大;
当滚动条滚动到页面底部时去加载下一页。
页面中所有的图片要延时加载。
原理:首先页面中的数据不能是写死的,是动态获取来的(AJAX),接着把数据绑定成 HTML。在插入到列之前,先给这些列按照高度进行升序排序,在插入数据时先给高度最矮的插,再给第二矮的插,最后给最高的插。这样就能保证最后高度相差不会太大。
关键问题
页面滚动到底去加载下一页:什么时候计算?页面滚动时,即 onscroll 事件触发时;
怎么计算?页面的 scrollHeight - 页面的 scrollTop - 浏览器可视窗口的高度 <= 0 表示已经滚到到底了
所以就是在页面的 onscroll 事件中去计算剩余高度,当剩余高度为0就表示要到底了。
html
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>花瓣网瀑布流效果</title><!-- IMPORT CSS --><link rel="stylesheet" href="css/reset.min.css"><link rel="stylesheet" href="css/index.css"></head><body><div class="container clearfix"><!-- column列 --><div class="column"><!-- item每一项 --><!-- <a class="item" href=""><div class="imgBox"><img src="img/1.jpg" alt=""></div><p>泰勒·斯威夫特(Taylor Swift),1989年12月13日出生于美国宾州,美国歌手、演员。2006年出道,同年发行专辑《泰勒·斯威夫特》,该专辑获得美国唱片业协会的白金唱片认证</p></a> --></div><div class="column"></div><div class="column"></div></div><!-- IMPORT JS --><script src="js/jquery-1.11.3.min.js"></script><script src="node_modules/underscore/underscore.js"></script><script src="js/index.js"></script></body></html>
css
html,body {background: #E4E4E4;overflow-x: hidden;}.container {box-sizing: border-box;margin: 20px auto;width: 1000px;/* display: flex; 基于 FLEX 实现水平排列,里面的每一项都会保持相同的高度,其中某一项变高,其余所有的项也都跟着变高 */}.container .column {box-sizing: border-box;float: left;margin-right: 20px;width: 320px;}.container .column:nth-last-child(1) {margin-right: 0;}.container .column .item {display: block;padding: 10px;margin-bottom: 10px;background: #FFF;box-shadow: 3px 3px 10px #666;}.container .column .item .imgBox {/* height: 300px; 想要实现图片延迟加载,这块显示默认占位图,事先需要知道图片的高度(从服务获取的数据中有图片高度) */background: url("../img/default.gif") no-repeat center center #EEE;overflow: hidden;}.container .column .item .imgBox img {display: none;width: 100%;}.container .column .item p {margin-top: 10px;font-size: 12px;color: #555;line-height: 20px;}
css清除默认样式用
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,button,input,textarea,th,td{margin:0;padding:0}body{font-size:12px;font-style:normal;font-family:"\5FAE\8F6F\96C5\9ED1",Helvetica,sans-serif}small{font-size:12px}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4,h5,h6{font-size:100%}ul,ol{list-style:none}a{text-decoration:none;background-color:transparent}a:hover,a:active{outline-width:0;text-decoration:none}table{border-collapse:collapse;border-spacing:0}hr{border:0;height:1px}img{border-style:none}img:not([src]){display:none}svg:not(:root){overflow:hidden}html{-webkit-touch-callout:none;-webkit-text-size-adjust:100%}input,textarea,button,a{-webkit-tap-highlight-color:rgba(0,0,0,0)}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]),video:not([controls]){display:none;height:0}progress{vertical-align:baseline}mark{background-color:#ff0;color:#000}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}button,input,select,textarea{font-size:100%;outline:0}button,input{overflow:visible}button,select{text-transform:none}textarea{overflow:auto}button,html [type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted ButtonText}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-cancel-button,[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.clear:after{display:block;height:0;content:"";clear:both}

js
/** debounce:函数防抖* @params* func:要执行的函数* wait:间隔等待时间* immediate:在开始边界还是结束边界触发执行(TRUE=>在开始边界)* @return* 可被调用的函数*/function debounce(func, wait, immediate) {let result = null,timeout = null;return function (...args) {let context = this,now = immediate && !timeout;clearTimeout(timeout); // 重要:在设置新的定时器之前,我们要把之前设置的定时器都干掉,因为防抖的目的是等待时间内,只执行一次timeout = setTimeout(() => {timeout = null;if (!immediate) result = func.call(context, ...args);}, wait);if (now) result = func.call(context, ...args);return result;}}let flowModule = (function () {let $columns = $('.column'),_DATA = null;// queryData:基于 AJAX 从服务器获取数据let queryData = function () {$.ajax({url: 'json/data.json',method: 'GET',async: false,success: result => {_DATA = result;}});};// bindHTML:实现页面中的数据绑定let bindHTML = function () {// 瀑布流实现的原理:每一次从 _DATA 中取出三条数据,按照三列由矮到高的顺序依次插入for (let i = 0; i < _DATA.length; i += 3) {// 把数据按照图片由高到低排序let group = _DATA.slice(i, i + 3);if (i !== 0) {group.sort((A, B) => B.height - A.height);}// 先按照高度排序(升序)$columns.sort((A, B) => {// A / B原生 JS 元素对象,想要使用 JQ 的方法,需要转换为 JQ 对象let $A = $(A),$B = $(B);return $A.outerHeight() - $B.outerHeight();}).each((index, column) => {// _DATA[i+index] 计算出要往每一列中插入的数据// let dataItem = _DATA[i + index];let dataItem = group[index];// 没有数据,说明数据都已经处理完了,我们结束循环if (!dataItem) return false;let {pic, height, title, link} = dataItem;$(column).append(`<a class="item" href="${link}"><div class="imgBox" style="height:${height}px"><img src="" alt="" data-img="${pic}"></div><p>${title}</p></a>`);});}// 实现图片延迟加载:数据绑定完,延迟 1000MS 加载真实的图片setTimeout(lazyImgs, 1000);};// lazyImgs:图片延迟加载let lazyImgs = function () {let $imgBoxs = $('.container .imgBox[isLoad!="true"]'),$window = $(window),B = $window.outerHeight() + $window.scrollTop();// 循环每一个图片(图片盒子),计算其底边距离 BODY 的偏移,从而验证出是否加载真实图片$imgBoxs.each((index, imgBox) => {let $imgBox = $(imgBox),$img = $imgBox.children('img'),A = $imgBox.outerHeight() + $imgBox.offset().top;// if ($imgBox.attr('isLoad') === "true") return;if (A <= B) {// 加载真实图片$imgBox.attr('isLoad', 'true');$img.attr('src', $img.attr('data-img'));$img.on('load', () => {// $img.css('display', 'block'); // 直接显示$img.stop().fadeIn(); // 基于 JQ 动画渐现显示});}});};// loadMore:加载更多数据let loadMore = function () {// 滚动到底端(一屏幕高度+卷去的高度+500>=页面真实的高度),加载更多数据let $window = $(window),winH = $window.outerHeight(),scrollT = $window.scrollTop(),pageH = $(document).height();if (winH + scrollT + 500 >= pageH) {queryData();bindHTML();}};return {init: function () {queryData();bindHTML();// 滚动条滚动处理一些事情window.onscroll = _.throttle(function () {// 延迟加载图片lazyImgs();// 加载更多数据loadMore();}, 50);}}})();flowModule.init();

