整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

网页图片预加载实现的几个方法解析

页中预加载图片是提高用户体验的一个很好方法。图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度。这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速加载,特别是一些大型的电商网站就常用!帮助用户在浏览你网站内容时获得更好的用户体验,下面就来说说实现图片预加载的方法。

一、使用JavaScript实现预加载

提供两种这样的预加载方法,它们可以很漂亮地工作于所有现代浏览器之上。

只需简单编辑、加载所需要图片的路径与名称即可,很容易实现:

该方法尤其适用预加载大量的图片。画廊网站使用该技术,预加载图片数量达50多张的时候。将该脚本应用到登录页面,只要用户输入登录帐号,大部分画廊图片将被预加载。

另外一种方法与上面的方法类似,也可以预加载任意数量的图片。将下面的脚本添加入任何Web页中,根据程序指令进行编辑即可。

每加载一个图片都需要创建一个变量,如“img1 = new Image();”,及图片源地址声明,如“img3.src = "../path/to/image-003.gif";”。参考该模式,你可根据需要加载任意多的图片。

二、用CSS实现预加载

单纯使用CSS,可容易、高效地预加载图片,代码如下:

#preload-01 { background: url(-01.png) no-repeat -9999px -9999px; }#preload-02 { background: url(-02.png) no-repeat -9999px -9999px; }#preload-03 { background: url(-03.png) no-repeat -9999px -9999px; }

将这三个ID选择器应用到HTML元素中,我们便可通过CSS的background属性将图片预加载到屏幕外的背景上。只要这些图片的路径保持不变,当它们在Web页面的其他地方被调用时,浏览器就会在渲染过程中使用预加载(缓存)的图片。简单、高效,不需要任何JavaScript。

者:麦乐

来源:恒生LIGHT云社区

图像延迟加载

想要得到更好的性能体验,只靠资源压缩与恰当的文件格式选型,是很难满足期望的。我们还需要针对资源加载过程进行优化。

什么是延迟加载?

下图是京东商城的手机端首页,当元素没有滑动到视线内时,图片src属性放置了一个很小的图片,init_src属性放置了真正的图片,只要当该元素滑动到视线内部,才会将init_src属性赋值给src去加载真实的图片,这就是一个简单的图片延迟加载的过程。

传统方式延迟加载

就是事件监听的方式,通过监听scroll事件与resize事件,并在事件的回调函数中去判断,需要进行延迟加载的图片是否进入视窗区域。

我们只需要关注三个属性。

  • class属性,稍后会在JavaScript中使用类选择器选取需要延迟加载处理的〈img〉标签。
  • src属性,加载前的占位符图片,可用Base64图片或低分辨率的图片。
  • data-src属性,通过该自定义属性保存图片真实的URL外链。

加入页面中有多张这样的图片需要加载。具体的JavaScript实现逻辑如下,在文档的DOMContentLoaded事件中,添加延迟加载处理逻辑,首先获取class属性名为lazy的所有〈img〉标签,将这些标签暂存在一个名为lazyImages的数组中,表示需要进行延迟加载但还未加载的图片集合。当一个图片被加载后,便将其从lazyImages数组中移除,直到lazyImages数组为空时,表示所有待延迟加载的图片均已经加载完成,此时便可将页面滚动事件移除。

这里使用了getBoundingClientRect()函数获取元素的相对位置.

        rectObject = object.getBoundingClientRect();

rectObject.top:元素上边到视窗上边的距离;

rectObject.right:元素右边到视窗左边的距离;

rectObject.bottom:元素下边到视窗上边的距离;

rectObject.left:元素左边到视窗左边的距离;

对于只可上下滚动的页面,判断一个图片元素是否出现在屏幕视窗中的方法其实显而易见,即当元素上边缘距屏幕视窗顶部的top值小于整个视窗的高度window.innerHeight时,预加载的事件处理代码如下:

document.addEventListener(DOMContentLoaded, function() {
      const imags = [].slice.call(document.querySelector('.lazy'))
      const active = false; // 限制函数被频繁调动
      function load() {
        if(active === false) {
          active = true
          setTimeout(() => {
            imags.forEach((img) => {
              const objPos = img.getBoundingClientRect();
              if(objPos.top <= window.innerHeight && objPos.bottom >=0 && img.display !== 'done') {
                img.src = img.dataset.src;
                img.classList.remove('lazy')
                imags.filter((i) => (i !== img))
                if(imags.length === 0) {
                  document.removeEventListener('scroll', load)
                  window.removeEventListener('resize', load)
                  window.removeEventListener('orientationchange', load)
                }
  
              }
            })
            active = false
          }, 200)
        }

      }

      document.addEventListener('scroll', load)
      window.addEventListener('resize', load)
      window.addEventListener('orientationchange', load)

    })

这种方式的有点就是兼容性比较好,缺点是频繁地进行计算必然会影响性能,代码也会比较繁琐。

实现图片的延迟加载:Intersection Observer方式

现代浏览器已大多支持了Intersection Observer API,用一句话简述:每当因页面滚动或窗口尺寸发生变化,使得目标元素(target)与设备视窗或其他指定元素产生交集时,便会触发通过Intersection Observer API配置的回调函数,在该回调函数中进行延迟加载的逻辑处理,会比传统方式显得更加简洁而高效。

简单来说,目标元素的可见性变化时,就会调用观察器的回调函数 callback

callback一般会触发两次。一次是目标元素刚刚进入视口(开始可见),另一次是完全离开视口(开始不可见)。

 document.addEventListener(DOMContentLoaded, function() {
        const imags = [].slice.call(document.querySelector('.lazy'))
        if(window.IntersectionObserver && window.IntersectionObserverEntry && window.IntersectionObserverEntry.prototype.intersectionRatio) {
          var lazyImgObserver = new IntersectionObserver((entries, observer) => {
            entries.forEach((entry)=> {
              if(entry.isIntersecting) {
                var lazyImg = entry.target;
                lazyImg.src = lazyImg.dataset.src;
                lazyImg.classList.remove('lazy');
                lazyImgObserver.unobserve(lazyImg)
              }
            })
          })
          imags.forEach((img) => {
            lazyImgObserver.observe(img)
          })
        }
   
      })

这种方式判断元素是否出现在视窗中更为简单直观,应在实际开发中尽量使用,但其问题是并非所有浏览器都能兼容。

(1)做好尽量完备浏览器兼容性检查,对于兼容Intersection Observer API的浏览器,采用这种方式进行处理,而对于不兼容的浏览器,则切换回传统的实现方式进行处理。 (2)使用相应兼容的polyfill插件,在W3C官方GitHub账号下就有提供。

实现图片的延迟加载:CSS类名方式

这种实现方式通过CSS的background-image属性来加载图片,与判断〈img〉标签src属性是否有要请求图片的URL不同,CSS中图片加载的行为建立在浏览器对文档分析基础之上。

  document.addEventListener(DOMContentLoaded, function() {
        const imags = [].slice.call(document.querySelector('.lazy'))
        if(window.IntersectionObserver && window.IntersectionObserverEntry && window.IntersectionObserverEntry.prototype.intersectionRatio) {
          var lazyImgObserver = new IntersectionObserver((entries, observer) => {
            entries.forEach((entry)=> {
              if(entry.isIntersecting) {
                var lazyImg = entry.target;
                lazyImg.classList.add('visible');
                lazyImgObserver.unobserve(lazyImg)
              }
            })
          })
          imags.forEach((img) => {
            lazyImgObserver.observe(img)
          })
        }
   
      })

这种方式限制于需要提前写好css样式。

原生的延迟加载支持

除了上述通过开发者手动实现延迟加载逻辑的方式,从Chrome 75版本开始,已经可以通过〈img〉和〈iframe〉标签的loading属性原生支持延迟加载了,loading属性包含以下三种取值。

● lazy:进行延迟加载。 ● eager:立即加载。 ● auto:浏览器自行决定是否进行延迟加载。

测试:image标签就是 img

<!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>
  <!-- <script src="js/file2.js"></script> -->
  <!-- <script src="js/file3.js"></script> -->
  <!-- <link rel="stylesheet" href="css/index.css"> -->
  <style>
    img {
      width: 700px;
      height: 200px;
      display: block;
    }
  </style>
</head>
<body>

  
  
  <imgage loading="lazy" src='./image/home-1.png' alt="photo" />
  <imgage loading="lazy" src='./image/home-2.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-3.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-4.png' alt="photo" />
  <imgage loading="lazy" src='./image/home-5.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-6.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-7.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-8.png' alt="photo" />
  
  <imgage loading="lazy" src='./image/home-9.png' alt="photo" />
  <imgage loading="lazy" src='./image/home-10.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-11.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-12.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-13.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-14.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-15.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-16.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-17.png' alt="photo" />
  <imgage loading="lazy" src='./image/home-18.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-19.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-20.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-21.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-22.png' alt="photo" />
  
  <imgage loading="lazy" src='./image/home-23.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-24.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-25.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-26.png' alt="photo" />
  <imgage loading="lazy" src='./image/home-27.png' alt="photo" />

  <imgage loading="lazy" src='./image/home-28.png' alt="photo" />


  <imgage loading="lazy" src='./image/home-29.png' alt="photo" />

<imgage loading="lazy" src='./image/home-30.png' alt="photo" />



</body>
</html>

可以看到,首次加载的个数是13个,首屏一般只能放下4个左右,13个以后的img滚动到视线内部会自动去加载。

实践发现有以下几个特点:

  1. Lazy loading加载数量与屏幕高度有关,高度越小加载数量越少,但并不是线性关系。
  2. Lazy loading加载数量与网速有关,网速越慢,加载数量越多,但并不是线性关系。
  3. Lazy loading加载没有缓冲,滚动即会触发新的图片资源加载。
  4. Lazy loading加载在窗口resize尺寸变化时候也会触发,例如屏幕高度从小变大的时候。
  5. Lazy loading加载也有可能会先加载后面的图片资源,例如页面加载时滚动高度很高的时候。

与JavaScript有关的几个行为特征:

  1. 判断浏览器是否支持原生loading,最好使用'loading' in XXX判断。
  2. 获取loading属性值可以直接img.loading;
  3. 原生loading不可写,不可访问例如HTMLImageElement.prototype.loading会报错Illegal invocation。
  4. 如果要使用,注意做兼容性处理。

两天被django折磨的快崩溃了。要做一个网页,结果CSS 和图片总是加载不出来。官方文档中教了一部分,上网看乐各种教程都不行,研究了好几个小时,东拼西凑各个地方学一点,终于弄出来了,赶紧记录下来。

django用的静态文件路径:STATICFILES_DIRS部署的方式,文件路径一定要设置好。

注: python2.7 django1.10.6; 项目mysite,项目下有一个应用myapp

一、目录结构:

整个目录结构是这样的:

| mysite

| —— manage.py

| —— mysite

| —— | —— settings

| —— | ——…(urls等)

| —— templates

| —— myapp

| —— …(views等)

| —— | —— templates

| —— | —— | —— myapp

| —— | —— | —— | —— home.html

| —— | —— | —— | —— static

| —— | —— | —— | —— | —— css

| —— | —— | —— | —— | —— images

注意,文件夹结构比较复杂。

在项目文件夹下有一个templates文件夹,不过这个文件夹暂时没什么用,可以不用管(我也不知道为什么要有这么个文件夹)。

应用文件夹结构是这样的:

“myapp/templates/myapp/home.html”;

“myapp/templates/myapp/static/images”;

“myapp/templates/myapp/static/CSS”;

二、设置templates和静态路径

  • 在settings.py中设置templates路径

TEMPLATES = [

{

'BACKEND': 'django.template.backends.django.DjangoTemplates',

'DIRS': [os.path.join(BASE_DIR, 'myapp/templates').replace('\', '/'),

os.path.join(BASE_DIR, 'templates').replace('\', '/')],

}

]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 在settings.py文件的最后加上以下内容:

STATIC_ROOT = os.path.join(BASE_DIR, 'myapp/templates/myapp/static').replace('\', '/')

STATICFILES_DIRS = (

('css', os.path.join(STATIC_ROOT, 'css').replace('\', '/')),

('images', os.path.join(STATIC_ROOT, 'images').replace('\', '/')),

)

  • 1
  • 2
  • 3
  • 4
  • 5

三、修改urls.py文件

在urls.py开头加上一句:

from django.contrib.staticfiles.urls import staticfiles_urlpatterns

  • 1

在urls.py的最后加上以下内容:

#设置静态文件路径

urlpatterns += staticfiles_urlpatterns()

  • 1
  • 2

四、修改html文件

home.html文件相关内容如下:

<!DOCTYPE html>

<html lang="en">

<head>

<link href="/static/css/style.css" rel="stylesheet" type="text/css" />

<title>Home</title>

</head>

<body>

<a href="https://www.baidu.com/>

<img src="/static/images/logo.png" alt="logo"/>

</a>

</body>

</html>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

改成自己的图片名称,注意图片和link的前缀:/static/images/ 别写成 static/images/ ,这样会无法显示。

感觉自己底子真的太差,这几天一点一点看官方文档感到非常吃力,很多地方都不懂,想直接看自己需要的部分又不知道该看哪。