五分钟学会图片懒加载和瀑布流

这次我们来学习图片的懒加载,又叫图片延迟(按需)加载

在需要的时候加载图片

比如我们在逛淘宝时,淘宝整个页面的图片并不是一下子就全部加载出来的,而是我们滚动到哪就加载哪里的图片。

这样可以更好的加载页面的首屏内容,无需考虑整个页面,

图片懒加载的实现

我为大家准备了如下代码,方便大家学习

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        img {
            width: 300px;
            height: 300px;
        }
    </style>
</head>

<body>
    <div>
        <img src="./" alt="" data-src="../images/OIP-C.jpg">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/f9.png">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/垃圾回收.png">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/小樱花.webp">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/f9.png">
    </div>
    <script src="../jQuery/jquery-1.12.4.js"></script>
    <script>
        var images = document.getElementsByTagName("img");
        images = $.makeArray(images)
        function isInVisibleArea(img) {
            var rect = img.getBoundingClientRect();//实时的
            return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
        }
        function lazyLoad() {
            for (var i = 0; i < images.length; i++) {
                var img = images[i]
                // 判断是否在可视区域
                if (isInVisibleArea(img)) {
                    img.src = img.dataset.src
                    images.splice(i, 1)
                    i--
                }
            }
        }
        lazyLoad()
        window.addEventListener("scroll", lazyLoad, false)
    </script>
</body>

</html>

在代码中,我们有多涨图片且不能同时在一个页面一次性展示,然后我们为图片添加自定义属性data-src来存储将要加载的路径

<body>
    <div>
        <img src="./" alt="" data-src="../images/OIP-C.jpg">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/f9.png">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/垃圾回收.png">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/小樱花.webp">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/f9.png">
    </div>
</body>

我们先导入jquerry框架

<script src="../jQuery/jquery-1.12.4.js"></script>

然后再script标签中首先获取所有的img

,因为获取的是一个伪数组,不可以用数组的方法,我们需要将其转换成数组,这里我用jquerry的makeArray方法转成数组,然后循环数组

for (var i = 0; i < images.length; i++) {
                var img = images[i]
                // 判断是否在可视区域
                if (isInVisibleArea(img)) {
                   
                }
            }

用一个声明一个img接收每一个img

然后if判断图片是否在可视区域

这里我们需要封装一个isInVisibleArea(img)函数判断图片是否在可视区域

 function isInVisibleArea(img) {
            var rect = img.getBoundingClientRect();//实时的
            return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
        }

 getBoundingClientRect()方法可以获取当前元素在页面的上下左右位置

此时 if执行,让本来没有加载(路径错误)的src替换成自定义的data-src

每次都要删除一个img,然后自减

基本完成

但是我们会发现只有在刷新页面的时候会判断一次是否在可视区域

那么这时我们要封装一个函数lazyload,将刚才的佛如循环封装起来

function lazyLoad() {
            for (var i = 0; i < images.length; i++) {
                var img = images[i]
                // 判断是否在可视区域
                if (isInVisibleArea(img)) {
                    img.src = img.dataset.src
                    images.splice(i, 1)
                    i--
                }
            }
        }
        lazyLoad()
        window.addEventListener("scroll", lazyLoad, false)

然后在全局调用一次,再给window绑定scroll事件实时监听滚动事件

到此

代码编写完成,我们可以f12检查network实时刷新的数据可以发现,只有在可是界面的图片才会被加载。

全部代码:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        img {
            width: 300px;
            height: 300px;
        }
    </style>
</head>

<body>
    <div>
        <img src="./" alt="" data-src="../images/OIP-C.jpg">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/f9.png">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/垃圾回收.png">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/小樱花.webp">
    </div>
    <div>
        <img src="./" alt="" data-src="../images/f9.png">
    </div>
    <script src="../jQuery/jquery-1.12.4.js"></script>
    <script>
        var images = document.getElementsByTagName("img");
        images = $.makeArray(images)
        function isInVisibleArea(img) {
            var rect = img.getBoundingClientRect();//实时的
            return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
        }
        function lazyLoad() {
            for (var i = 0; i < images.length; i++) {
                var img = images[i]
                // 判断是否在可视区域
                if (isInVisibleArea(img)) {
                    img.src = img.dataset.src
                    images.splice(i, 1)
                    i--
                }
            }
        }
        lazyLoad()
        window.addEventListener("scroll", lazyLoad, false)
    </script>
</body>

</html>

瀑布流

瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。最早采用此布局的网站是Pinterest,逐渐在国内流行开来。国内大多数清新站基本为这类风格。 

在这里插入图片描述

 (本文主要介绍JS实现部分,html部分甚为简略,后会将代码一同贴在文章结尾处)

特点

1.瀑布流对用户来说有着很强的吸引力,瀑布流会在它的页面底部给用户不断地加载新的暗示信息,通过给出不完整的视觉图片去吸引你的好奇心,让你停不下来地想要向下不断地探索。

2、瀑布流的信息较为集中,可以在最小的操作成本下能够获得最多的内容体验,因此瀑布流能更好的适应移动端,由于移动设备屏幕比电脑小,一个屏幕显示的内容不会非常多,因此可能要经常翻页。而在建网站时使用瀑布流布局,用户则只需要进行滚动就能够不断浏览内容。

3、另外瀑布流的主要特质就是:定宽而不定高,这样的页面设计区别于传统的矩阵式图片布局模式,巧妙的利用视觉层级,视线的任意流动来缓解视觉的疲劳。

实现原理

瀑布流有两大特征

1.内容框宽度固定,高度不固定。 2.内容框从左到右排列,一行排满后,其余内容框就会按顺序排在短的一列后。

(可以用最小二叉树来类比瀑布流的形成算法) 

因此在某种程度上瀑布流的实现原理与最小二叉树类似

首先我们先通过计算一行能够容纳几列元素(因为我们需要在不同的设备上浏览)

在这里插入图片描述

然后在通过计算比较找出这一列元素中高度之和最小一列

(假设就是我们框起来的这一列) 

在这里插入图片描述

然后将下一行的第一个元素添加至高度之和最小的这一列的下面

在这里插入图片描述

然后继续计算所有列中高度之和最小的那一列,然后继续将新元素添加至高度之和最小的那一列后面,直至所有元素添加完毕。

在这里插入图片描述

实现步骤及算法

1.将图片导入,后将其统一定位为 position:relative

    #container{
        position: relative;
    }

2.建立一个JS文件并在html文件中引入

	<script src="./index.js"></script>

3.全局监听每一张图片加载时的状况,以备后续图片的安放

window.onload = function () {
    imgLocation('container', 'box')
}

4.拿到页面上所有要摆放的图片的数量

function imgLocation(parent, content) {
	var cparent = document.getElementById(parent)
	var ccontent = getChildElemnt(cparent, content)
}

function getChildElemnt(parent, content) {
    const contentArr = []
    const allContent = parent.getElementsByTagName('*')
	//取到‘parent’中的所有的子容器
    for (var i = 0; i < allContent.length; i++) {
        if (allContent[i].className == content) {
            contentArr.push(allContent[i])
        }
    }
    // 取到想要的子容器的数量
    return contentArr
}
	//这里也可以使用dom的querySelectorAll()方法

5.找到图片的宽度和需要图片进行插入的位置

	var imgWidth = ccontent[0].offsetWidth
	//拿到图片的宽度
	var num = Math.floor(document.documentElement.clientWidth / imgWidth)
	//得到一横行可以放置图片的数量
	cparent.style.cssText = `width: ${imgWidth * num} px`
	 

6.在确切位置上放置需要被放置的图片,并进行循环,将该页面上的所有图片按需要的位置加入

    var BoxHeightArr = []
    for (var i = 0; i < ccontent.length; i++) {
        if (i < num) {
            BoxHeightArr[i] = ccontent[i].offsetHeight
        } else {
            var minHeight = Math.min.apply(null, BoxHeightArr)
            var minIndex = getMinHeightLocation(BoxHeightArr, minHeight)
            ccontent[i].style.position = 'absolute'
            ccontent[i].style.top = minHeight + 'px'
            ccontent[i].style.left = ccontent[minIndex].offsetLeft + 'px'
            BoxHeightArr[minIndex] = BoxHeightArr[minIndex] + ccontent[i].offsetHeight
        }
    }
    function getMinHeightLocation(BoxHeightArr, minHeight) {
    for (var i in BoxHeightArr) {
        if (BoxHeightArr[i] === minHeight) {
            return i
        }
    }
}

代码分享

HTML

<!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>js 瀑布流</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        #container{
            position: relative;
        }
        .box{
            float: left;
            padding: 5px;
        }
        .box-img{
            width: 150px;
            padding: 5px;
            border: 1px solid #ccc;
            box-shadow: 0 0 5px #ccc;
            border-radius: 5px;
        }
        .box-img img{
            width: 100%;
            height: auto;
        }
    </style>
</head>

<body>
    <div id="container">
        <div class="box">
            <div class="box-img">
                <img src="./img/1.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/2.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/3.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/4.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/5.jpg" alt="">
            </div>
        </div>
    </div>

    <script src="./index.js"></script>
</body>

</html>

JS

window.onload = function () {
    imgLocation('container', 'box')
}

// 获取到当前有多少张图片要摆放
function imgLocation(parent, content) {
    // 将parent下所有的内容全部取出
    var cparent = document.getElementById(parent)
    var ccontent = getChildElemnt(cparent, content)
    var imgWidth = ccontent[0].offsetWidth
    var num = Math.floor(document.documentElement.clientWidth / imgWidth)
    cparent.style.cssText = `width: ${imgWidth * num} px`

    var BoxHeightArr = []
    for (var i = 0; i < ccontent.length; i++) {
        if (i < num) {
            BoxHeightArr[i] = ccontent[i].offsetHeight
        } else {
            var minHeight = Math.min.apply(null, BoxHeightArr)
            var minIndex = getMinHeightLocation(BoxHeightArr, minHeight)
            ccontent[i].style.position = 'absolute'
            ccontent[i].style.top = minHeight + 'px'
            ccontent[i].style.left = ccontent[minIndex].offsetLeft + 'px'
            BoxHeightArr[minIndex] = BoxHeightArr[minIndex] + ccontent[i].offsetHeight
        }
    }
    // console.log(BoxHeightArr);
}


function getChildElemnt(parent, content) {
    const contentArr = []
    const allContent = parent.getElementsByTagName('*')
    // console.log(allContent);
    for (var i = 0; i < allContent.length; i++) {
        if (allContent[i].className == content) {
            contentArr.push(allContent[i])
        }
    }
    // console.log(contentArr);
    return contentArr
}

function getMinHeightLocation(BoxHeightArr, minHeight) {
    for (var i in BoxHeightArr) {
        if (BoxHeightArr[i] === minHeight) {
            return i
        }
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值