前言
众所周知,图片的加载是前端页面加载性能的优化之一。如果一个页面在加载的时候全部加载当前页面的图片,当图片资源比较多且比较大(质量)的时候会严重影响页面的加载。特别是SPA应用,先加载jsbundle资源,再去加载图片资源,这样就会更加影响页面的加载性能。
一般我们优化页面加载的时候通常有一下几种方案:
- 把
CSS
文件放在页面顶部,而javascript
文件放在底部 - 去掉不必要的js脚本插件
- 利用浏览器缓存
- 使用
CSS Sprites
整合图像 - 压缩
CSS
和javascript
脚本 - 启用
gzip
压缩 - 优化图像
- 减少
DNS
查询 - 最小化重定向
本文编写的插件主要是从在加载页面的时候减少图片的请求来优化页面加载性能。下面分享一下使用rollup打包的懒加载图片插件。下面手把手教你撸一个图片懒加载插件,开始上车了...
初始化项目
创建img-lazyload目录,执行下边命令
cd img-lazyload
npm init -y
安装配置rollup
安装插件
npm install -D @babel/core @babel/preset-env
npm install -D rollup rollup-plugin-babel rollup-plugin-commonjs rollup-plugin-node-resolve rollup-plugin-uglify
@babel/core
babel
的核心插件必不可少
@babel/preset-env
es6
转化es5
的插件,因为代码使用了es6
新特性,需要配置babel
rollup
rollup
核心包必不可少
rollup-plugin-babel
如果使用了babel
,需要这个插件
-
rollup-plugin-commonjs
node_modules
中的包大部分都是commonjs
格式的,要在rollup
中使用必须先转为ES6
语法,所以需要安装插件 但是本项目代码没有使用其它插件,这个包可以不安装,也可以不用添加commonjs
的配置 -
rollup-plugin-node-resolve
rollup无法识别node_modules中的包,需要插件告诉 Rollup 如何搜寻外部依赖,但是本项目代码没有使用其它插件,这个包可以不安装,也可以不用添加resolve
配置
rollup-plugin-uglify
压缩打包js代码
配置rollup
打包js
代码
建build/rollup.config.js
, src/index.js
文件
src/index.js
这里编写代码,先添加下边代码
console.log("hello world");
build/rollup.config.js
配置代码如下
这里只写了简单的配置
import { uglify } from 'rollup-plugin-uglify'
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs' // commonjs规范的代码转化es6
import babel from 'rollup-plugin-babel'
export default {
input: 'src/index.js', // 打包入口
output: {
file: 'dist/index.min.js', // 输出文件
format: 'umd', // 打包格式,支持浏览器,也支持commonjs
name:"ImgLazyLoad", // 编译浏览器环境的包时需要指定name属性
},
plugins:[
babel({
exclude: ['node_modules/**']
}), // 支持babel
resolve(), // 查找包路径
commonjs(), // 支持commonjs的插件
uglify(), // 压缩代码的插件
],
}
到这里简单的配置已经完成,下边我们检查配置是否成功
添加打包命令在package.json
中
"build": "rollup --config build/rollup.config.js"
我们执行npm run build
,会看到生成一个dist/index.js
文件,下边这个就是我们打包生成的最终代码
然后编写demo进行测试打包是否成功
新建example/index.html
编写代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,viewport-fit=cover">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="renderer" content="webkit|ie-comp|ie-stand">
<meta http-equiv="x-dns-prefetch-control" content="on">
<title>图片懒加载测试</title>
</head>
<body>
<div id="app">
</div>
<script src="./../dist/index.min.js"></script>
</body>
</html>
这是主要是需要把打包的代码在html中进行加载<script src="./../dist/index.js"></script>
打开静态html,调出控制台。console.log("hello world")
正常执行。说明rollup的配置可以打包
现在我们初始化项目完成,下边编写图片懒加载代码
图片懒加载源码
删除src/index.js
的测试代码,编写如下代码
/*
* 图片懒加载对象
* */
function ImgLazyLoad(className) {
if (!this instanceof ImgLazyLoad) {
console.warn('ImageLazy is a constructor and should be called with the `new` keyword')
return;
}
// 判断类名是否为null
if(!className) return;
// 获取className的Node节点
this.imageList = [...document.querySelectorAll(className)];
if(this.imageList && this.imageList.length >0){
// 初始化的时候需要先去执行一下滚动监听方法,需要首屏图片加载出来
this.pageScroll();
this.initScrollEvent();
}
}
/*
* 初始化监听滚动事件
* */
ImgLazyLoad.prototype.initScrollEvent = function(){
window.addEventListener('scroll',()=>{
this.imageList.length && this.pageScroll();
})
}
/*
* 监听滚动的回调方法
* */
ImgLazyLoad.prototype.pageScroll = function(){
let imgs = this.imageList;
const replacedIndexList = [];
for(let i = 0;i < imgs.length;i++){
// 判断当前图片是否在屏幕当前显示区域(这里做了一个小技巧,当图片的头部离屏幕底部60px开始加载图片的地址,防止图片过大且滑动过快的时候显示空白区域)
if(imgs[i].getBoundingClientRect().top - 60 <= window.innerHeight){
this.replaceImgSrc(imgs[i]);
replacedIndexList.push(i);
}
}
const array = [];
// 把加载过的图片从数组中移除
for(let i = 0;i < imgs.length;i++){
if(replacedIndexList.indexOf(i) <= -1){
array.push(imgs[i])
}
this.imageList = array;
}
}
/*
* 替换属性,正式加载图片
* */
ImgLazyLoad.prototype.replaceImgSrc = function(el){
if(el){
// 将图片替换为真实地址,加载图片
let src = el.getAttribute('original-src');
el.src = src;
}
}
export default ImgLazyLoad;
运行npm run build
构建源代码发现编译报错
经过排查发现时babel没有配置
在项目根目录新建babel.config.js文件,代码如下:
module.exports = {
presets: ['@babel/preset-env']
};
重新执行npm run build
构建源代码发现无报错
完善Demo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,viewport-fit=cover">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="renderer" content="webkit|ie-comp|ie-stand">
<meta http-equiv="x-dns-prefetch-control" content="on">
<title>图片懒加载测试</title>
<style>
html , body {
margin: 0;
padding: 0;
}
img {
width: 100%;
}
.one {
width: 359px;
height: 538px;
}
.two {
width: 359px;
height: 385px;
}
.three {
width: 359px;
height: 638px;
}
</style>
</head>
<body>
<div id="app">
<div>
<h3>第一张图片</h3>
<img original-src="http://t7.baidu.com/it/u=3616242789,1098670747&fm=79&app=86&f=JPEG?w=900&h=1350" src="" class="lazy one" alt=""/>
</div>
<h2>这是占用文字测试demo</h2>
<h2>这是占用文字测试demo</h2>
<h2>这是占用文字测试demo</h2>
<h2>这是占用文字测试demo</h2>
<div>
<h3>第二张图片</h3>
<img src="" original-src="http://t8.baidu.com/it/u=3571592872,3353494284&fm=79&app=86&f=JPEG?w=1200&h=1290" class="lazy two" alt=""/>
</div>
<h2>这是占用文字测试demo</h2>
<h2>这是占用文字测试demo</h2>
<h2>这是占用文字测试demo</h2>
<h2>这是占用文字测试demo</h2>
<h2>这是占用文字测试demo</h2>
<div>
<h3>第三张图片</h3>
<img src="" original-src="http://img1.imgtn.bdimg.com/it/u=3527822447,3068369850&fm=26&gp=0.jpg" class="lazy three" alt=""/>
</div>
</div>
<script src="./../dist/index.min.js"></script>
<script>
new ImgLazyLoad(".lazy") //必须使用new创建,而且只能在dom加载完毕才可以实现这个功能
</script>
</body>
</html>
打开静态src/index.html,调出控制台,查看元素。如下图
QQ截图20200314134823.png发现加载页面的时候,第二,三张图片没有加载。上拉页面的时候,当图片快要出现在屏幕的时候,图片src被替换成了真实的图片地址,这时候才真正加载图片。
这里到此结束,这个项目还有不足之处。
用在spa项目中,只能在单独组件使用(而且必须在组件的加载完成生命周期方法之后),不能一次创建永久使用
谢谢!
网友评论