js原生瀑布流,懒加载,触底加载混合案例小记


额,算了   直接上代码,注释写的挺详细的没必要再介绍了--哈~~

直接复制打开就可以看到效果-

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .waterfall {
            width: 100vw;
            display: flex;
            flex-wrap: wrap;
            position: relative;
        }
        .item {
            width: 200px;
            background-color: #ccc;
            position: absolute;
            vertical-align: top;
        }
    </style>
</head>

<body>
    <!-- 瀑布流  指的是一种布局方式 有两种模式 确定宽度  确定列  在这写的是确定宽度-->
    <!-- 瀑布流 + 图片懒加载 + 触底加载 -->
    <div class="waterfall" id="container">
        <!-- <img class="item"
            data-src="https://ts3.cn.mm.bing.net/th?id=OIP-C.Rq5h9rKa8uBoUxtGTCCVRQHaKd&w=210&h=297&c=8&rs=1&qlt=90&o=6&dpr=2&pid=3.1&rm=2"
            alt="" src=""> -->
    </div>
    <script>
        /***
         * 本案例主要做的是瀑布流布局(固定列宽) + 触底加载 + 图片懒加载   瀑布流懒加载不能结合
         * 瀑布流     是对现有的进行布局    
         * 懒加载     是对不在视觉内的图片的操作
         * 触底       是指页面数据加载完成并滚动到了页面底部要加载新数据
         * 思路:
         * 有个容器   开始搞
         * imgs1 = []    图片路径    
         * 思路:--   -- 可忽略  
         * -- 
         * 触底很好做   就是这个懒加载    懒加载的前提 是要判断元素在不在页面中   
         * 我做一张图   图加载完 就布局一次 在做一张图 加载之前先看一看在不在页面中 
         * 陷入了悖论  灵感-后端传来的是图片源信息   src都设置完成了   才布局   只有布局之后才能判断要不要设置src   (只能在有一个已经加载完了  这个不在页面内了  夏夜个肯定不在页面内  就停止设置src)
         * --
         */

         // 模拟后端传来的源信息  有宽高   20一组
        let imgs1 = [
            {path:'https://ts3.cn.mm.bing.net/th?id=OIP-C.Rq5h9rKa8uBoUxtGTCCVRQHaKd&w=210&h=297&c=8&rs=1&qlt=90&o=6&dpr=2&pid=3.1&rm=2', width:200, height:284},
            {path:'https://ts3.cn.mm.bing.net/th?id=OIP-C.atTl-J5TF3GE5FWfRtTIygHaJ8&w=215&h=289&c=8&rs=1&qlt=90&o=6&dpr=2&pid=3.1&rm=2', width:200, height:270},
            {path:'https://ts3.cn.mm.bing.net/th?id=OIP-C.QFdwl07_aviM1ch2KpyyFgHaEo&w=316&h=197&c=8&rs=1&qlt=90&o=6&dpr=2&pid=3.1&rm=2', width:200, height:125},
            {path:'https://ts1.cn.mm.bing.net/th?id=OIP-C.nfC2tVNM9TgwQ5QuqECd6wHaFj&w=288&h=216&c=8&rs=1&qlt=90&o=6&dpr=2&pid=3.1&rm=2', width:200, height:150},
            {path:'https://ts2.cn.mm.bing.net/th?id=OIP-C.pgBMw_lMOYSOCZIDQ896NAHaLF&w=204&h=305&c=8&rs=1&qlt=90&o=6&dpr=2&pid=3.1&rm=2', width:200, height:300},
            {path:'https://ts1.cn.mm.bing.net/th?id=OIP-C.1-wFaNNsH_OCBFvGCfloWgHaJ4&w=216&h=288&c=8&rs=1&qlt=90&o=6&dpr=2&pid=3.1&rm=2', width:200, height:267},
            {path:'https://ts1.cn.mm.bing.net/th?id=OIP-C.ebfLNO07a781ncjScj7u6wHaLs&w=198&h=314&c=8&rs=1&qlt=90&o=6&dpr=2&pid=3.1&rm=2', width:200, height:318},
            {path:'https://tse4-mm.cn.bing.net/th/id/OIP-C.uNxOyVhFHzUweInZEahy-QHaFj?w=231&h=180&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:156},
            {path:'https://tse2-mm.cn.bing.net/th/id/OIP-C.XXrW8aTA10CkicQuGceNjgHaE7?w=263&h=180&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:137},
            {path:'https://tse2-mm.cn.bing.net/th/id/OIP-C.mQBvGOCQDvosB6SXXIljfwHaE0?w=304&h=197&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:130},
            {path:'https://tse3-mm.cn.bing.net/th/id/OIP-C.pVMgoYOCp9YQ3BnH1AhuggHaE7?w=296&h=197&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:135},
            {path:'https://tse1-mm.cn.bing.net/th/id/OIP-C.YTQX73HsbhdnueV0dzYPpAHaEW?w=314&h=184&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:120},
            {path:'https://tse4-mm.cn.bing.net/th/id/OIP-C.ivx7EPOK5Y3d4J_Z2OlydgHaE7?w=260&h=180&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:140},
            {path:'https://tse1-mm.cn.bing.net/th/id/OIP-C.h02sipGoXVxrZGX27e2hoQHaE3?w=234&h=180&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:154},
            {path:'https://tse4-mm.cn.bing.net/th/id/OIP-C.4eNrKDHGVHrdX45iP22r6AHaEK?w=283&h=180&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:125},
            {path:'https://tse1-mm.cn.bing.net/th/id/OIP-C.hNu5gDicpIJY8yCE-hM2EwHaNK?w=115&h=184&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:320},
            {path:'https://tse3-mm.cn.bing.net/th/id/OIP-C.MfAU3E769jbMcGoA-WrbHwHaEK?w=294&h=180&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:123},
            {path:'https://tse2-mm.cn.bing.net/th/id/OIP-C.lE3uaNuJUHCapn4EnEPFbgHaE8?w=267&h=180&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:135},
            {path:'https://tse4-mm.cn.bing.net/th/id/OIP-C.OjgEXcW8FmAnIoO0bwTldwHaEK?w=297&h=183&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:124},
            {path:'https://tse2-mm.cn.bing.net/th/id/OIP-C.y8bP8drHeoVXB53aMIQhIQAAAA?w=189&h=190&c=7&r=0&o=5&dpr=2&pid=1.7',width:200,height:202},
        ]

        // 获取容器元素
        let container = document.getElementById('container')
        // 造图片
        function createImg(imgItem) {
            let img = new Image()
            img.setAttribute('data-src',imgItem.path) 
            img.height = imgItem.height
            img.className = 'item'
            img.src = ''
            img.alt = 'loading...'
            return img
        }

        // 图片标签上树
        function loadImg(imgArr) {
            let nodeImgArr = []
            for(let i = 0; i < imgArr.length; i++) {
                container.appendChild(createImg(imgArr[i]))
            }
            // 上树完成之后  就布局
            waterfall()
        }

        // 瀑布流布局
        function waterfall() {
            // 得到所有图片和定义的间距
            let items =  document.getElementsByClassName('item')
            let padNum = 10
            // 确定有多少列
            let itemWidth =items[0].offsetWidth
            let columns = Math.ceil(getClient().width / (itemWidth + 10)) // 向下取整
            // 定义一个映射高度数组 * 核心
            let heightArr = []
            for (var i = 0; i < items.length; i++) {
                if (i < columns) {
                    // 表示是第一行
                    items[i].style.top = 0
                    items[i].style.left = i * (itemWidth + padNum) + 'px'
                    items[i].src = items[i].dataset['src']
                    heightArr.push(items[i].offsetHeight)
                    // 更新高度
                } else {
                    // 表示第二行开始了
                    // 要得到最小高度  以及最小高度所在的索引
                    let minHeight = Math.min(...heightArr)
                    let heightIdx = heightArr.findIndex((item, index) => item === minHeight)
                    // items[i]是否在可视区域
                    items[i].style.top = minHeight + padNum + 'px'
                    items[i].style.left = heightIdx * (itemWidth + padNum) + 'px'
                    // 判断是否在视口内
                    if(isInViewPort(items[i])) {
                        items[i].src = items[i].dataset['src']
                    }
                    // 更新高度
                    heightArr[heightIdx] += (items[i].clientHeight + padNum)
                }
            }
        }
        
        window.onload = function() {
            // 当这个图片数组已经渲染过了之后   就不需要再加载了
            loadImg(imgs1)

        }

        // 监听尺寸变化
        window.onresize = function() {
            waterfall()
            if(touchBottom()) {
                loadImg(imgs1)
            }
        }

        window.onscroll = function() {
            // 
            waterfall()
            // 
            if(touchBottom()) {
                loadImg(imgs1)
            }
        } 

        // 获取视口宽度 方法 -- 兼容
        function getClient() {
            return {
                width: window.innerWidth || document.documentElement.clientHeight || document.body.clientHeight,
                height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
            }
        }

        // 判断元素是否在视窗内
        function isInViewPort(element) {
            const viewWidth = window.innerWidth || document.documentElement.clientWidth;
            const viewHeight = window.innerHeight || document.documentElement.clientHeight;
            const {
                top,
                right,
                bottom,
                left,
            } = element.getBoundingClientRect();

            return (
                // top >= 0 &&
                // left >= 0 &&
                // right <= viewWidth &&
                // bottom <= viewHeight
                top >= 0 && (top + 30) <= viewHeight
            );
        }

        // 获取滚动值  方法  -- 兼容
        function getScrollTop() {
            return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
        }

        // 判断页面是否触底  //页面卷去高度 + 浏览器可视窗口的高度 >= 整个页面的高度
        function touchBottom() {
            return getScrollTop() + getClient().height + 10 >= document.body.scrollHeight
        }

    </script>
</body>

</html>

参考: 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是原生js实现图片懒加载的源码: ```javascript // 获取所有需要懒加载图片元素 const lazyImages = document.querySelectorAll("img.lazy"); // 判断图片是否在可视区域内 function isInViewport(image) { const rect = image.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } // 加载图片 function loadImage(image) { image.src = image.dataset.src; image.classList.remove("lazy"); } // 监听window的滚动事件 window.addEventListener("scroll", function () { // 遍历需要懒加载图片元素 for (const image of lazyImages) { if (isInViewport(image)) { loadImage(image); } } }); ``` 首先,我们获取所有需要懒加载图片元素: ```javascript const lazyImages = document.querySelectorAll("img.lazy"); ``` 接着,我们定义一个函数`isInViewport`用于判断图片是否在可视区域内。该函数会返回一个布尔值,表示图片是否在可视区域内: ```javascript function isInViewport(image) { const rect = image.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } ``` 然后,我们定义一个函数`loadImage`用于加载图片。该函数会将图片的`src`属性设置为`data-src`属性的值,并移除`lazy`类: ```javascript function loadImage(image) { image.src = image.dataset.src; image.classList.remove("lazy"); } ``` 最后,我们监听`window`的滚动事件,遍历所有需要懒加载图片元素,如果图片在可视区域内,则调用`loadImage`函数加载图片: ```javascript window.addEventListener("scroll", function () { for (const image of lazyImages) { if (isInViewport(image)) { loadImage(image); } } }); ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ankang_路上的小白

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

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

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

打赏作者

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

抵扣说明:

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

余额充值