瀑布流
-
在head里面需要加上这样一行代码
<meta name="referrer" content="no-referrer" />
-
CSS代码
<style> *{ margin: 0; padding: 0; } .container{ width: 1000px; margin: 0 auto; position: relative; } .box{ width: 235px; margin: 0 20px 20px 0; float: left; } .box:nth-of-type(4){ margin: 0 0 20px 0 ; } .box img{ width: 100%; } </style>
-
HTML代码
<div class="container"> </div>
-
javascript代码
<script src="./data.js"></script> <script> // 瀑布流的数据全部都放在了data.js 里面的data变量之中; // - 我们取出数据其实就是对全局变量的获取和使用; // - 我们直接把这个 data 数据当成数组对象来使用; // 排列规则 : // 把图片按照第一行排列分成四列, 后续的所有图片按照那一列短就往那一列上放元素的规则进行排列; // - 我们后续的元素排列方式都是以定位为主的; // - 元素定位需要几个位置信息 ? // - x , y ; // - 1. 渲染功能 : class WaterFall{ constructor(){ this.container = document.querySelector(".container"); this.data = data; this.render(); this.sort(); } render(){ // 渲染瀑布流数据的时候需要定死图片的高度; this.container.innerHTML = this.data.map(item => `<div class="box"> <img src="${ item.photo.path}" alt="" height=${ 235 / item.photo.width * item.photo.height}> </div>` ).join("") } sort(){ // 1. 获取元素,把元素进行分类; var boxs = document.querySelectorAll(".box"); // 2. 找到每一个box盒子,根据何在在boxs之中的位置进行分类; var position_array = []; for(var i = 0 ; i < boxs.length ;i ++){ if( i < 4 ){ // 创建基础数据; position_array.push({ left : boxs[i].offsetLeft, height : boxs[i].offsetHeight }) }else{ // 排列; // 1. 找到最小高度值; var res = this.getMin( position_array ); var min = res.min; var index = res.index; // 2. 给当前的元素赋值; boxs[i].style.position = "absolute"; boxs[i].style.left = min.left + "px"; boxs[i].style.top = min.height + 20 + "px"; // 3. 更改原数组数据; position_array[ index ].height += boxs[i].offsetHeight + 20 ; } } } getMin ( arr ){ var index = 0 ; var min = arr[ index ]; for(var i = 1 ; i < arr.length ; i ++){ if( arr[i].height < min.height ){ min = arr[i]; index = i; } } return { index : index, min : min } } } var wf = new WaterFall; </script>
- 引用的data.js代码
var data = [ { "photo": { "width": 700, "height": 1050, "path": "https://c-ssl.duitang.com/uploads/item/202001/09/20200109015939_qgxxp.jpg", "size": 123212, "file_type_code": 0 } }, { "photo": { "width": 960, "height": 540, "path": "https://c-ssl.duitang.com/uploads/blog/202105/30/20210530233801_cdb4d.jpg", "size": 232398, "file_type_code": 1 } }, { "photo": { "width": 1600, "height": 2843, "path": "https://c-ssl.duitang.com/uploads/item/202003/03/20200303101550_hzTJ8.jpeg", "size": 714276, "file_type_code": 0 } }, { "photo": { "width": 1080, "height": 1441, "path": "https://c-ssl.duitang.com/uploads/blog/202108/06/20210806104317_50f69.jpeg", "size": 314091, "file_type_code": 1 } }, { "photo": { "width": 1021, "height": 1361, "path": "https://c-ssl.duitang.com/uploads/blog/202108/06/20210806104312_bc0af.jpeg", "size": 236746, "file_type_code": 1 } }, { "photo": { "width": 1124, "height": 632, "path": "https://c-ssl.duitang.com/uploads/item/202003/19/20200319001841_pfmkr.jpg", "size": 342551, "file_type_code": 0 } }, { "photo": { "width": 1080, "height": 1440, "path": "https://c-ssl.duitang.com/uploads/blog/202108/05/20210805165151_450f5.jpeg", "size": 798985, "file_type_code": 1 } }, { "photo": { "width": 1081, "height": 1081, "path": "https://c-ssl.duitang.com/uploads/item/202003/29/20200329083438_hhqwn.jpg", "size": 611550, "file_type_code": 0 } }, { "photo": { "width": 1080, "height": 1347, "path": "https://c-ssl.duitang.com/uploads/item/202005/14/20200514165334_kcmwd.jpg", "size": 231613, "file_type_code": 0 } }, { "photo": { "width": 1080, "height": 1080, "path": "https://c-ssl.duitang.com/uploads/item/202004/11/20200411232939_kodou.jpeg", "size": 143626, "file_type_code": 0 } }, { "photo": { "width": 1200, "height": 1798, "path": "https://c-ssl.duitang.com/uploads/item/202004/01/20200401164316_i5rh2.jpeg", "size": 289833, "file_type_code": 0 } }, { "photo": { "width": 768, "height": 1151, "path": "https://c-ssl.duitang.com/uploads/blog/202102/02/20210202103749_a6828.jpeg", "size": 211091, "file_type_code": 0 } }, { "photo": { "width": 899, "height": 1200, "path": "https://c-ssl.duitang.com/uploads/item/202006/12/20200612070243_cmJjx.jpeg", "size": 242549, "file_type_code": 0 } }, { "photo": { "width": 1078, "height": 1076, "path": "https://c-ssl.duitang.com/uploads/item/202005/17/20200517003432_gwbes.jpg", "size": 389967, "file_type_code": 0 } }, { "photo": { "width": 690, "height": 682, "path": "https://c-ssl.duitang.com/uploads/item/202003/09/20200309143939_jt8Ql.jpeg", "size": 154296, "file_type_code": 0 } }, { "photo": { "width": 1080, "height": 1080, "path": "https://c-ssl.duitang.com/uploads/blog/202010/26/20201026180224_2271c.jpg", "size": 734052, "file_type_code": 0 } }, { "photo": { "width": 1124, "height": 1353, "path": "https://c-ssl.duitang.com/uploads/item/202005/20/20200520040511_ycwyp.jpg", "size": 692514, "file_type_code": 0 } }, { "photo": { "width": 988, "height": 987, "path": "https://c-ssl.duitang.com/uploads/blog/202008/17/20200817000959_rqqmv.jpg", "size": 486663, "file_type_code": 0 } }, { "photo": { "width": 983, "height": 984, "path": "https://c-ssl.duitang.com/uploads/item/202007/14/20200714031634_nwrpz.jpg", "size": 265194, "file_type_code": 0 } }, { "photo": { "width": 1080, "height": 1313, "path": "https://c-ssl.duitang.com/uploads/item/202006/14/20200614230406_dlfdh.jpg", "size": 848142, "file_type_code": 0 } }, { "photo": { "width": 1059, "height": 1057, "path": "https://c-ssl.duitang.com/uploads/item/202007/11/20200711121028_sdvvh.jpg", "size": 418997, "file_type_code": 0 } }, { "photo": { "width": 1080, "height": 1077, "path": "https://c-ssl.duitang.com/uploads/item/202006/14/20200614211532_shbzh.jpg", "size": 269825, "file_type_code": 0 } }, { "photo": { "width": 1193, "height": 1345, "path": "https://c-ssl.duitang.com/uploads/item/202005/26/20200526162311_xgtfd.jpg", "size": 298572, "file_type_code": 0 } }, { "photo": { "width": 1068, "height": 1067, "path": "https://c-ssl.duitang.com/uploads/item/202005/17/20200517003432_ybmsf.jpg", "size": 357992, "file_type_code": 0 } } ]
懒加载
- 懒加载是图片加载时一个重要的优化手段;
- 提高页面的性能,把我们的网络性能集中使用到关键的数据在上;
- 所谓的懒加载就是在页面卷动的时候判断哪些元素显示出来了;
- 显示出来的元素可以优先进行网络请求;
功能实现
-
CSS代码
<style> img{ width: 590px; height: 470px; display: block; } header{ height: 400px; background-color: skyblue; } .container{ position: relative; } </style>
-
html代码
<header></header> <div class="container"> //图片是随便在网上扒的 <img data-src="https://img30.360buyimg.com/pop/s1180x940_jfs/t1/180101/26/19460/98965/61197c43E0cd71669/58cef4e5d5143186.jpg.webp" alt=""> <img data-src="https://img14.360buyimg.com/pop/s1180x940_jfs/t1/193069/2/17935/76186/6115d06eEd2e6d523/da6fcd956b9f4871.jpg.webp" alt=""> <img data-src="https://img14.360buyimg.com/pop/s1180x940_jfs/t1/204277/40/626/83751/6111f5b6E1f4cebdb/6efe6b8addd1fc32.jpg.webp" alt=""> <img data-src="https://img30.360buyimg.com/pop/s1180x940_jfs/t1/186622/35/18008/96346/6114f7d8E6af9382a/bfbceb3f07dd2efd.jpg.webp" alt=""> <img data-src="https://imgcps.jd.com/ling4/100009077475/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5bd8253082acdd181d02fa33/497bcb5c/cr/s/q.jpg" alt=""> <img data-src="https://img10.360buyimg.com/pop/s1180x940_jfs/t1/201638/31/360/73951/610cf93fE36f0a982/da2e3f8b33de6361.jpg.webp" alt=""> <img data-src="https://imgcps.jd.com/ling4/100021802484/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5bd8253082acdd181d02f9df/2df51be8/cr/s/q.jpg" alt=""> <img data-src="https://img30.360buyimg.com/pop/s1180x940_jfs/t1/180101/26/19460/98965/61197c43E0cd71669/58cef4e5d5143186.jpg.webp" alt=""> <img data-src="https://img30.360buyimg.com/pop/s1180x940_jfs/t1/183652/4/18158/92117/6110e00cE609a93aa/b56b4a71064249ad.jpg.webp" alt=""> </div>
-
javascript代码
// 1. 阻止图片发起网络请求; // - 图片只有存在src才会发起网络请求; // - 如果我们给图片赋值src,那么图片会立即根据src发起网络请求加载图片数据; // 2. 明确了目标 : // - 图片可以显示的时候我们把data-src替换成src; // - 替换之后让图片发起网络请求; // 结论 : 如果图片offsetTop值小于了 scrollTop (页面隐藏的高度) + 页面的显示区域高度,那么我们就认为这个元素被显示了; // 获取所有图片元素,获取所有图片的高度; class LazyLoad{ constructor( selector ){ this.imgs = Array.from(document.querySelectorAll( selector )); this.top_list = this.imgs.map( ele => this.getAbsTop(ele) ); //BUG 只要页面不滚动,首屏图片是无法显示的; this.bindEvent(); window.dispatchEvent( new Event("scroll")); } getAbsTop( ele ){ // 你当前的定位元素是不是body; if( ele.offsetParent !== document.body){ return ele.offsetTop + this.getAbsTop( ele.offsetParent ) } return ele.offsetTop; } bindEvent(){ // 给页面绑定卷动事件; window.addEventListener("scroll" , ()=>{ for(var i = 0 ; i < this.top_list.length; i ++){ if( this.top_list[i] <= scrollY + innerHeight ){ // 图片如果已经加载了那就直接删除掉这个图片就可以了; this.imgs[i].src = this.imgs[i].getAttribute("data-src"); // 删除掉对应的元素和高度信息; this.imgs.splice( i , 1 ) this.top_list.splice( i , 1 ) i --; } } }) } } var ll = new LazyLoad("img");
函数节流去抖
函数节流
-
其实就是对函数执行频率的限制
-
在某段时间间隔之内执行一次函数
var t = null ; window.onscroll = function(){ //如果t不是null那么我们就不允许代码执行 if(t !== null){ return ; } t = setTimeout(() => { //放入你想要执行的代码 console.log("hello world"); //重置t t = null; }, 300); }
函数去抖
-
函数执行起来需要延迟300ms,如果在300ms之内再次执行了函数,那么重新计时
var t = null ; window.onscroll = function(){ //如果t不是null那么我们就不允许代码执行 clearTimeout(t); t = setTimeout(() => { //放入你想要执行的代码 console.log("hello world"); //重置t t = null; }, 300); }
函数节流封装
- 通过封装能够使得代码重复利用率更强。
var throttling = (function(){ var t = null ; return function(callback){ //如果t不是null那么我们就不允许代码执行 if(t !== null){ return ; } t = setTimeout(() => { //放入你想要执行的代码 callback(); t = null; }, 300); } })(); window.onscroll = function(){ throttling(function(){ console.log("hello world"); }) }
函数去抖封装
- 对函数去抖进行封装
var qudou = (function(){ var t = null; return function(callback){ clearTimeout(t); t = setTimeout(() => { callback() t = null; }, 300); } })(); window.onscroll = function(){ qudou(function(){ console.log("hello world"); }) }
功能合并
-
CSS代码和HTML代码与上面懒加载一直,这里就不再写了
-
JavaScript代码
class LazyLoad{ constructor( selector ){ this.imgs = Array.from(document.querySelectorAll( selector )); this.top_list = this.imgs.map( ele => this.getAbsTop(ele) ); //BUG 只要页面不滚动,首屏图片是无法显示的; this.bindEvent(); window.dispatchEvent( new Event("scroll")); } getAbsTop( ele ){ // 你当前的定位元素是不是body; if( ele.offsetParent !== document.body){ return ele.offsetTop + this.getAbsTop( ele.offsetParent ) } return ele.offsetTop; } bindEvent(){ // 给页面绑定卷动事件; window.addEventListener("scroll" , ()=>{ throttling(this.toggleAttr.bind(this)); }) } toggleAttr(){ console.log( 1 ); for(var i = 0 ; i < this.top_list.length; i ++){ if( this.top_list[i] <= scrollY + innerHeight ){ // 图片如果已经加载了那就直接删除掉这个图片就可以了; this.imgs[i].src = this.imgs[i].getAttribute("data-src"); // 删除掉对应的元素和高度信息; this.imgs.splice( i , 1 ) this.top_list.splice( i , 1 ) i --; } } } } var throttling = (function(){ var t = null; return function( callback , delay = 200){ // 如果t不是null那么我们就不允许代码执行; if( t !== null ){ return ; } t = setTimeout( function(){ // 放入你想要执行的代码; callback(); // 重置t; t = null; } , delay ) } })(); var ll = new LazyLoad("img");
瀑布流最终形态
-
CSS代码和HTML代码与瀑布流的一致
-
JavaScript代码如下
<script src="./data.js"></script> <script src="./utils.js"></script> <script> // - 1. 渲染功能 : class WaterFall{ constructor(){ this.container = document.querySelector(".container"); this.data = data; this.render(); this.sort(); new LazyLoad(".box img"); } render(){ // 渲染瀑布流数据的时候需要定死图片的高度; this.container.innerHTML = this.data.map(item => `<div class="box"> <img data-src="${ item.photo.path}" alt="" height=${ 235 / item.photo.width * item.photo.height}> </div>` ).join("") } sort(){ // 1. 获取元素,把元素进行分类; var boxs = document.querySelectorAll(".box"); // 2. 找到每一个box盒子,根据何在在boxs之中的位置进行分类; var position_array = []; for(var i = 0 ; i < boxs.length ;i ++){ if( i < 4 ){ // 创建基础数据; position_array.push({ left : boxs[i].offsetLeft, height : boxs[i].offsetHeight }) }else{ // 排列; // 1. 找到最小高度值; var res = this.getMin( position_array ); var min = res.min; var index = res.index; // 2. 给当前的元素赋值; boxs[i].style.position = "absolute"; boxs[i].style.left = min.left + "px"; boxs[i].style.top = min.height + 20 + "px"; // 3. 更改原数组数据; position_array[ index ].height += boxs[i].offsetHeight + 20 ; } } } getMin ( arr ){ var index = 0 ; var min = arr[ index ]; for(var i = 1 ; i < arr.length ; i ++){ if( arr[i].height < min.height ){ min = arr[i]; index = i; } } return { index : index, min : min } } } var wf = new WaterFall; </script>
- 引用的data.js代码如上面一样,这里不再书写
- 引用的utils.js代码如下:
var throttling = (function(){ var t = null; return function( callback , delay = 200){ // 如果t不是null那么我们就不允许代码执行; if( t !== null ){ return ; } t = setTimeout( function(){ // 放入你想要执行的代码; callback(); // 重置t; t = null; } , delay ) } })(); class LazyLoad{ constructor( selector ){ this.imgs = Array.from(document.querySelectorAll( selector )); this.top_list = this.imgs.map( ele => this.getAbsTop(ele) ); //BUG 只要页面不滚动,首屏图片是无法显示的; this.bindEvent(); window.dispatchEvent( new Event("scroll")); } getAbsTop( ele ){ // 你当前的定位元素是不是body; if( ele.offsetParent !== document.body){ return ele.offsetTop + this.getAbsTop( ele.offsetParent ) } return ele.offsetTop; } bindEvent(){ // 给页面绑定卷动事件; window.addEventListener("scroll" , ()=>{ throttling(this.toggleAttr.bind(this)); }) } toggleAttr(){ for(let i = 0 ; i < this.top_list.length; i ++){ if( this.top_list[i] <= scrollY + innerHeight ){ // 图片如果已经加载了那就直接删除掉这个图片就可以了; let loadImg = new Image(); loadImg.src = this.imgs[i].getAttribute("data-src"); let img = this.imgs[i] loadImg.onload = ()=>{ img.src = img.getAttribute("data-src"); } this.imgs.splice( i , 1 ) this.top_list.splice( i , 1 ) i--; // 删除掉对应的元素和高度信息; } } } }
处理图片断裂情况
产生原因
- 因为图片过大,在加载时浏览器为了让用户可以看到加载结果所以分段落进行加载/解析
- 我们可以对图片进行预加载,然后再进行src赋值
在进行图片加载的时候我们可以创建一个img图片,对图片进行加载,图片加载结束,让src赋值给页面上的图片就可以了 - 浏览器对图片是有缓存的
-
HTML代码
<img data-src="https://c-ssl.duitang.com/uploads/item/202003/03/20200303101550_hzTJ8.jpeg" alt="" width="235px">
-
javascript代码
<script> var img = document.querySelector("img"); document.onclick = function(){ var loadImg = new Image(); loadImg.src = img.getAttribute("data-src"); // 当缓存图片加载结束,我们就可以对其进行赋值; loadImg.onload = function(){ img.src = img.getAttribute("data-src"); } } </script>
原创不易,转载请注明出处。