基于canvas的图像预加载
在图片多的页面中,为了提高用户体验,我们会对图片进行压缩,采用更小的图片格式让图片尽可能快的展现给用户。在浏览medium.freecodecamp.com中一些文章时,偶然发现在网速不好的时候,会先看到一张模糊的图片,然后再展示出清晰的图。于是打开控制台抓了一下资源,发现展现出的第一张模糊的图片大小只有30*30。通过预加载一张小的图片,可以快速的展示给用户一些东西,减少中间的空白时间。看一看源码,发现是基于cancas来实现的。下面来看看它是怎么做的吧
首先我们有两张图
一张是原始图像:
另一张是 30*30 的小图:
图片展示的 html 结构如下,原始图像我们先通过 visibility:hidden 隐藏起来。
1 2 3 4 5
| <div class="img-container is-canvasLoaded" img-src="./demo.png"> <img src="./demo_min.png" id="imgdemo" alt="" style="opacity:0;position: absolute;z-index: -1;"> <canvas id="canvas-container"></canvas> <img src="./demo2.png" alt="" id="origin-img" style="opacity:0"> </div>
|
初始时设置 canvas 的大小略大于我们的 demo_min.png 图片,如 75 * 75,然后:
- 获取 demo_min.png 大小 60 * 30
- 根据 demo_min.png 的比例,设置一下 canvas 的比例 75 * 37.5
1 2 3 4 5 6 7 8 9 10 11
| var imgDemoSize = { width: imgDemo.offsetWidth, height: imgDemo.offsetHeight } var scale = imgDemoSize.width / imgDemoSize.height > canvasSize.width / canvasSize.height ? canvasSize.width / imgDemoSize.width : canvasSize.height / imgDemoSize.height var scaleSize = { width: imgDemoSize.width * scale, height: imgDemoSize.height * scale, } canvasDom.width = scaleSize.width canvasDom.height = scaleSize.height
|
现在html结构如下:
1 2 3 4 5
| <div class="img-container is-canvasLoaded" img-src="./demo.png"> <img src="./demo_min.png" id="imgdemo" alt="" style="opacity:0;position: absolute;z-index: -1;"> <canvas id="canvas-container" width="75" height="37></canvas> <img src="./demo2.png" alt="" id="origin-img" style="opacity:0"> </div>
|
将图像画在 canvas 上:
1 2 3
| var context = canvasDom.getContext('2d') context.drawImage(imgDemo, 0,0,60,30,0,0,75,37)
|
canvas 的 drawImage 方法的第一个参数,允许是 HTMLImageElement 。所以这里直接用 img 元素比较方便。图像画在 canvas 上之后,我们就可以通过 canvas 的 getImageData 方法来获取图像的像素,然后对图像进行高斯模糊处理。模糊处理这里直接使用了 stackblur.js 。想了解高斯模糊原理的可以参考高斯模糊的算法
1 2
| var imgData = context.getImageData(0,0,75,37) var blurImgData = StackBlur.imageDataRGBA(imgData, 0,0, 75, 37, 5);
|
模糊处理完之后,putImageData 放在 canvas 中
1
| context.putImageData(blurImgData, 0, 0);
|
然后展示 canvas , 到此页面上会展示一张模糊的图。
模糊图片出来了,原始图像什么时候展示呢?
使用 Img 的 load 事件,原始的图像加载完成后触发 load 事件,将 canvas 隐藏,展示原始图像。
1 2 3 4
| imgOrigin.addEventListener('load', function () { imgOrigin.style.opacity = 1 canvasDom.style.opacity = 0 })
|
在网速略慢时,我们就会看到页面上会先出现一张模糊的图,然后再呈现出清晰的图。此外可以用 css 的 transition 属性,增加模糊图和原始图 opacity 过度时间,让图片之间的切换看起来更为自然顺畅。