JavaScript学习之瀑布流和懒加载及函数节流去抖与图片断裂处理

瀑布流

  • 在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>
    

原创不易,转载请注明出处。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河不识

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值