nuxt 如何预加载大图片

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nuxt 如何预加载大图片相关的知识,希望对你有一定的参考价值。

图片预加载的主要思路就是把稍后需要用到的图片悄悄的提前加载到本地,因为浏览器有缓存的原因,如果稍后用到这个url的图片了,浏览器会优先从本地缓存找该url对应的图片,如果图片没过期的话,就使用这个图如下是摘录具体的实现思路《javascript图片预加载详解》图片的加载速度往往影响着网站整体的用户体验,尤其对于包含大量图片的网站。对图片进行预加载,不失为一个高效的解决方案。如何实现预加载?本文将例举利用CSS、JavaScript及ajax实现图片预加载的三大方法。

Perishable Press网站近日发表了一篇文章《3 Ways to Preload Images with CSS, JavaScript, or Ajax》,分享了利用CSS、JavaScript及Ajax实现图片预加载的三大方法。下面为译文。

预加载图片是提高用户体验的一个很好方法。图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度。这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速、无缝地发布,也可帮助用户在浏览你网站内容时获得更好的用户体验。本文将分享三个不同的预加载技术,来增强网站的性能与可用性。

方法一:用CSS和JavaScript实现预加载

实现预加载图片有很多方法,包括使用CSS、JavaScript及两者的各种组合。这些技术可根据不同设计场景设计出相应的解决方案,十分高效。

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

该方法虽然高效,但仍有改进余地。使用该法加载的图片会同页面的其他内容一起加载,增加了页面的整体加载时间。
在该脚本的第一部分,我们获取使用类选择器的元素,并为其设置了background属性,以预加载不同的图片。
该脚本的第二部分,我们使用addLoadEvent()函数来延迟preloader()函数的加载时间,直到页面加载完毕。如果JavaScript无法在用户的浏览器中正常运行,会发生什么?
参考技术A 这个概念就是写一个CSS样式设置一批背景图片,然后将其隐藏,这样你就看不到那些图片了。那些背景图片就是你想预载的图片。

前端项目分析:我是如何做图片优化的(预加载懒加载和延迟加载)

众所周知:前端页面上的图片是优化时最重要也是最令人头疼的部分,花费了几个月的时间才优化到令自己满意的一半程度,,,唉,一言难尽啊! 在此将几种方法总结一下,希望能帮到不少人吧…

图片的优化有两种方式: 预加载懒加载

先说说 预加载 :我以前到是写过关于预加载的博客,但是吧,,,里面很多内容不是让我很满意,因为后期发现有些内容在特定情况下才能显现出作用。
预加载的常用场景:在开发的过程,我们经常会遇到这样的要求,当鼠标hover上去的时候,更改菜单的背景。如果没有进行图片预加载的话,会出现闪烁。那么拥有1px的眼睛的设计师们不会放过你的。为什么会出现这张情况?因为hover的时候,图片才会去加载。
这个时候,就需要用预加载(在hover之前加载完(但会增加页面加载时间))了,
比如下面的:

<script type="text/javascript">
     <!--//--><![CDATA[//><!--
     if (document.images) 
         img1 = new Image();
         img2 = new Image();
         img1.src = "img/QQ图片20190521233736.jpg";
         img2.src = "img/Cache_3fa28786e3750c51..jpg";
     
     //--><!]]>
 </script>

如果需要预加载的图片太多的话可以这样:

var imgSrcArr=[
   '要预加载的图片路径'(可以多个啊)
];
var imgWrap=[];
function preloadImg(arr) 
    for(var i=0;i<arr.length;i++)
        imgWrap[i]=new Image();
        imgWrap[i].src=arr[i];
    

preloadImg(imgSrcArr);

$(function () 
    preloadImg(imgSrcArr);
)

也是预加载的经典了,最下面那三行意思是:或者等到文字加载完再加载图片。

网上还有人说可以采用ajax请求的方式,呵!你有那么多带宽何必做优化呢。。。

试验了很多场景,发现:预加载其实更适合如hover变换后的图片加载(解决闪屏问题),在网页刚打开的那个图片环境要求下其实作用不大。所以,我们可以将其放在需要响应鼠标事件(说白了,就是刚上去时不需要看见)的地方。

但是我的主要要求是首屏加载图片优化,提高用户体验,怎么办呢?
预加载好像帮不了我,,,
思量再三,我决定 “投靠” 懒加载 大军!

何为 “懒加载”?
在图片由于某些原因没有显示出来时,用一个占位符去显示,这是提高用户体验的不错方式,目前,京东等商城网站上就用了此技术。
懒加载的精髓:不要将真正图片放在src中引入,src中放“占位图”!

为什么使用懒加载:
在一个页面中,假设有20张图片,每张为100kb,用户在不点滚动条的时候看到的只有4张,如果这20张图片都设置了真正的src,那么当页面首次加载的时候浏览器会立即请求这20张图片资源,需要2000kb的流量;
但是我们做懒加载只请求用户看到的4张图片的话,浏览器只请求这4张图片资源,需要的流量只有400kb。这种手段可以大大减少首屏时间。

使用代码展示:(如何使用及js插件文件)

index.html

<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <style>
            body
                text-align: center;
            
            .game-detail-logo
                width: 750px;
                height: 430px;
                text-align: center;
                margin-top:30px;
            
        </style>
        <img src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=4259389730,3152819071&fm=26&gp=0.jpg" class="game-detail-logo lazyLoadImg" picAddress="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=4003935283,4035293154&fm=27&gp=0.jpg">
        <img src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=4259389730,3152819071&fm=26&gp=0.jpg" class="game-detail-logo lazyLoadImg" picAddress="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2390937513,1169699994&fm=27&gp=0.jpg">
    </body>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>   /*用http方式引入jQuery文件(min指压缩过的)*/
    <script type="text/javascript" src="lazyLoadImg.js"></script>
</html>

如上,在几张图片中,我们将 真正的图片 放在picAddress中,在src中放 占位图
在js中,页面加载完成后,根据scrollTop(滚动事件)重复判断图片是否在用户的视野内,如果在,则将picAddress属性中的值取出存放到src属性中。
lazyLoadImg.js(可直接使用)

/* 
* @example
* <img src="" class="lazyLoadImg" picAddress="">
* @param src里面写的是占位图或者说兜底图地址(一张默认填充图)
* @param class="lazyLoadImg" 是必须的标识
* @param picAddress里面写的是真正需要懒加载的图片地址
*/
const lazyLoadImg = 
  initConfig() 
    const self = this;
    self.imgObject.srcFlag = 'picAddress'; // 图片地址
    self.imgObject.class = 'lazyLoadImg'; // 惰性加载的图片需要添加的class
    self.imgObject.sensitivity = 40; // 鼠标滚动敏感度,该值越小,惰性越强(加载越少)
    self.imgObject.init();
  ,
  imgObject: 
    trigger() 
      const self = this;
      const eventType = (self.isPhone && 'touchend') || 'scroll';
      self.imgListData = $('img.' + self.class + '');
      $(window).trigger(eventType);
    ,
    init() 
      var self = this;
      $(window).on('scroll', function() 
        self.isLoadImg();
      );
      self.trigger();
    ,
    isLoadImg() 
      const self = this;
      function loadNeedImg(img)  // 判断哪些img元素需要加载
        const windowPageYOffset = window.pageYOffset; // 滚动条距离窗口顶部的偏移量
        const offsetAddInner = window.pageYOffset + window.innerHeight; // window.innerHeight返回窗口的文档显示区的高度
        const imgOffsetTop = img.offset().top; // 当前img元素距离窗口顶部的偏移量
        return (
          imgOffsetTop >= windowPageYOffset && // 确保img元素在窗口内
          imgOffsetTop - self.sensitivity <= offsetAddInner //当前img元素是不是在窗口可见范围内,不可见返回:false
        );
      
      function loadImg(img, index) 
        const imgUrl = img.attr(self.srcFlag);
        const imgLazy = img.attr('src');
        img.attr('src', imgUrl);
        img[0].onload ||  // 开始向服务器请求加载图片
          ((img[0].onload = function() 
            $(this)
              .removeClass(self.class)
              .removeAttr(self.srcFlag),
            (self.imgListData[index] = null),
            (this.onerror = this.onload = null);
          ),
            (img[0].onerror = function() 
              (this.src = imgLazy),
              $(this)
                .removeClass(self.class)
                .removeAttr(self.srcFlag),
              (self.imgListData[index] = null),
              (this.onerror = this.onload = null);
            ));
      
      self.imgListData.each(function(index, val) 
        if (!val) return;
        const img = $(val);
        if (!loadNeedImg(img)) return;
        const aa = img.attr(self.srcFlag);
        if (!img.attr(self.srcFlag)) return;// 判断是否有规定的picAddress属性,没有则退出当次循环
        loadImg(img, index);
      );
    ,
  ,
;
lazyLoadImg.initConfig();

(这里说明一下,网上有很多jQuery的.lazyload的包,但是个人使用过感觉兼容性和效果都巨差,故而提倡自己封装一个js)

这里要提一下jQuery封装过的代码(先引入jQuery包,极其简单):

<img src="imag/2.png" width="1920" height="340" alt="林允儿">
<!--有时为什么会有水平之间的空隙?回车符-->
<script>
    $('img').lazyload(
        //以“背景”的形式突出占位图
        placeholder:'imag/loading.gif',
        //视图滚动到这里时再加载原图
        effect:'fadeIn',
        //开始加载位置
        threshold:-170
    );
</script>

当然,我们也可以用js使图片以 渐进式 方式显示出来,就是从非常模糊(如 filter: blur(20vw) 玻璃模糊)逐步清晰。有位前辈告诉我说,这种方式本质上和 懒加载 是一个原理: 在“视图区”让一个属性(图片)替换另一个属性(图片)

<body>
<h3>懒加载咯 - 下面代码尤其适用于移动端页面开发(因为js-for中循环图片的判断方式,对竖直排列的图片最有利!)</h3>
<div class="imgs">
    <div>
        <img src="占位图" data-src="真正图片" alt="图片说明">
    </div>
    ...
</div>
<script>
    window.onload=function () 
        var imgs=document.querySelectorAll('img');
        function offset(el)
			let top=el.offsetTop
			while(el.offsetParent)
				el=el.offsetParent
				top+=el.offsetTop   //scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离
			
			return
				top
			
		
        function lazyload(imgs) 
            var h=window.innerHeight;   //innerheight	返回窗口的文档显示区的高度
            var s=document.documentElement.scrollTop || document.body.scrollTop;   //document.body.scrollTop 网页被卷去的高
            for(var i=0;i<imgs.length;i++)
                if((h+s)>offset(imgs[i]).top)   //窗口文档显示去高度+向上滚动的高度,判断是否到达了图片的位置,如果到了,才去加载,并在加载中 用一个动图去“占位”
                    (function (i) 
                        setTimeout(function () 
                            var tmp=new Image();
                            tmp.src=imgs[i].getAttribute("data-src");   //   直接获取
                            tmp.onload=function () 
                                imgs[i].src=imgs[i].getAttribute("data-src");   //   如果直接获取不了(还没加载完),就等加载完前面的再去获取
                            
                        ,1300)
                    )(i)
                
            
        
        lazyload(imgs);
        window.onscroll=function () 
            lazyload(imgs);
        
    
</script>
</body>

SVG: 在测验中发现,貌似svg格式的图片“更能使人疯狂”,这还不是重点。重要的是 ,我们可以把hover写在svg标签里,来解决hover时才加载图片的困境:

<svg>
	<style type="text/css">
		.st0fill:#282828;
		.st0:hoverfill:#3399cc;
	</style>
</svg>

但是 ,这种方法劣势极大,一旦图片和文字是“一体”的,事情就会非常棘手,要么变成跨域问题,要么会倍增HTML文件的体积。不管怎样,这里只是提一下这种方法,并不推荐使用,关于hover的困境,还是要靠预加载实现。


2020-08-11插入
其实除了上面的预加载和懒加载,我们还可借助 es6 - promise 实现 图片延迟加载

<body>
	<img src="img/loading.gif" data-src="https://dss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2860774393,2141973361&fm=58" alt="">
	<img src="img/loading.gif" data-src="https://dss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=1069388867,2729276042&fm=58" alt="">
	<img src="img/loading.gif" data-src="https://dss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=1188214717,3310596202&fm=58" alt="">
	
	<script>
		let imgDoms=document.querySelectorAll('img')
		let arr=[]
		for(let i in imgDoms)
			let p=new Promise((resolve,reject)=>
				var img=new Image();
				img.src=imgDoms[i].getAttribute('data-src');
				img.onload=()=>
					resolve(img)
				
				img.onerror=(e)=>
					reject(e)
				
			)
			arr.push(p)
		
		Promise.all(arr).then((res)=>
			console.log(res)
			for(let i in res)
				imgDoms[i].setAttribute('src',res[i].getAttribute('src'))
			
		).catch((err)=>
			console.log('图片加载失败')
		)
	</script>
</body>

现在让我们来想这样一个场景:我们将这段代码放在 页面加载complete 中,这样页面在初始环境加载时会只去请求占位极小的“GIF图”,在真正去加载图片时又因为promise而不得不异步地一个一个请求。

这对页面的性能体验也是极有帮助的。


分析适用场景,选择合适的方式才能将一个网站打造的更完美。
项目地址:

  1. http://cjxnsb.cn/mxc/UCgzs/1.html
  2. http://cjxnsb.cn/mxcf/index.html

以上是关于nuxt 如何预加载大图片的主要内容,如果未能解决你的问题,请参考以下文章

nuxt 优化项:禁用js的预加载

懒加载和预加载

关于图片预加载的思考

JS实现图片预加载无需等待

图片预加载的几个注意点

Preload图片预加载(jQuery插件)