[关闭]
@wy 2018-09-27T15:31:23.000000Z 字数 2245 阅读 541

img懒加载在onload之前拿到宽高

javascript


在前端这边经常做 img 的懒加载,会在 onload 事件触发后拿到图片的宽高,onload 的意思是在图片全部加载后会触发的事件,如果图片没加载之前是不会触发的。这样如果图片比较大,加载的时间过长,会导致本来显示图片的位置没有图片的实际宽高,只有等图片加载完成后才能确定显示图片区域的宽高。这样在做一些瀑布流时候,显得不那么的友好。

因为本地测试加载图片太快,所以使用后端控制图片的响应速度,基于 node 的框架 express 实现:

  1. const express = require('express')
  2. const app = express();
  3. const path = require('path');
  4. const fs = require('fs');
  5. app.use((req,res,next) => {
  6. let url = req.url;
  7. let extname = path.extname(url);
  8. if(extname === '.jpg'){
  9. let d = fs.createReadStream(__dirname+'/img/'+url);
  10. let chunks = [];
  11. var size = 0;
  12. let list = []
  13. res.set({
  14. 'Content-type':'image/jpg'
  15. });
  16. d.on("data", function (chunk){
  17. chunks.push(chunk);
  18. size += chunk.length;
  19. list.push(function (){
  20. return new Promise((resolve) => {
  21. setTimeout(() => {
  22. res.write(chunk);
  23. resolve();
  24. },500)
  25. });
  26. })
  27. });
  28. d.on("end", async function () {
  29. var buf = Buffer.concat(chunks, size);
  30. for( var i = 0; i < list.length; i++ ){
  31. await list[i]();
  32. }
  33. res.end()
  34. });
  35. }
  36. })
  37. app.listen(3000,() => {
  38. console.log('服务启动成功');
  39. })

整体的意思是当访问图片时候,不是一次性全部响应到前端,而是根据 fs 模块读流的方式一点点发给前端,这样的目的就是为了测试在图片没加载完成之前,可以获取到图片的宽高。

前端代码:

  1. <!DOCTYPE html>
  2. <html lang="zh-cn">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title></title>
  6. <style>
  7. .ketang {
  8. width:0px;
  9. height:0px;
  10. background: red;
  11. }
  12. .hello {
  13. background: blue;
  14. margin: 10px;
  15. float: left;
  16. }
  17. .hello img {
  18. width: 100%;
  19. height: 100%;
  20. }
  21. </style>
  22. <script src="./img_load.js"></script>
  23. <script>
  24. window.onload = function(){
  25. let arr = (new Array(9)).fill('').map((item,index) => {
  26. return 'http://localhost:3000/'+(index + 1) + '.jpg'
  27. });
  28. let hello = document.getElementsByClassName('hello')
  29. arr.forEach((url,index) => {
  30. imgReady(url,function(){
  31. console.log(url,this.width);
  32. hello[index].style.width = this.width / 5 + 'px';
  33. hello[index].style.height = this.height / 5 + 'px';
  34. },function (){
  35. console.log('loaded')
  36. hello[index].innerHTML = '<img src="'+url+'" alt="" />'
  37. })
  38. })
  39. };
  40. </script>
  41. </head>
  42. <body>
  43. <div class ="ketang" id="ketang">
  44. <img src="" id="test">
  45. </div>
  46. <div class="hello"></div>
  47. <div class="hello"></div>
  48. <div class="hello"></div>
  49. <div class="hello"></div>
  50. <div class="hello"></div>
  51. <div class="hello"></div>
  52. <div class="hello"></div>
  53. <div class="hello"></div>
  54. <div class="hello"></div>
  55. <div class="hello"></div>
  56. </body>
  57. </html>

这里用到了一个 img_load.js 库,参考:https://gist.github.com/southill/7149306

以上的原理很简单,当第一次读到图片的部分信息后,就把它发送到了前端,里面包含了图片的信息,这样不等图片全部加载好就可以拿到图片的地址。

在前端这边开启定时器,不断的访问加载的图片,一旦第一次加载的信息拿到后,立马就能得到图片的宽高。这时候你的图片可能还没有加载完,还没有出发onload事件。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注