LQIP
图片占位符大家肯定不陌生。现在主流的网站,例如博客 Medium、知乎等都支持了从模糊到清晰的图片加载效果,带来很棒的产品浏览体验。
LQIP 是 Low Quality Image Placeholders 的缩写,就是在这背后默默做出贡献的基础技术。这个技术可以根据原始图片自动生成超小尺寸的缩略图。
zouhir/lqip: Low Quality Image Placeholders (LQIP) Module for Node
与之相关的还有 SQIP,就不多讲了。相关资料:
直接使用 lqip
来维护图片是一件很痛苦的事情,所以不如利用前端工程的方法将其自动化。而 lqip-loader
是用其导入集成到 webpack 的 loader,进而不需要我们手动处理相关的文件内容,只需从源码里导入和使用即可。
zouhir/lqip-loader: Low Quality Image Placeholders (LQIP) for Webpack
配置方案
直接使用 lqip-loader 集成到 webpack 的方案:
配置方案一
使用 file-loader
{
/**
* 配置方案一
* 使用 file-loader
**/
test: /\.(png|jpe?g)$/,
loaders: [
{
loader: 'lqip-loader',
options: {
path: '/media', // your image going to be in media folder in the output dir
name: '[name].[ext]', // you can use [hash].[ext] too if you wish,
base64: true, // default: true, gives the base64 encoded image
palette: true // default: false, gives the dominant colours palette
}
}
]
}
配置方案二
结合其他 loader
{
/**
* 配置方案二
* 结合其他 loader
**/
test: /\.(png|jpe?g)$/,
loaders: [
{
loader: 'lqip-loader',
options: {
base64: true,
palette: false
}
},
{
loader: 'url-loader',
options: {
limit: 8000
}
}
]
}
集成到 Umi
本人使用的脚手架是 Umi ,因此需要用其提供的 chainwebpack
将lqip-loader
导入。
通过翻阅了其源码(umi/getConfig.ts at master · umijs/umi),可以知道图片处理相关的规则集为images
然后需要在 url-loader
前将 lqip-loader
导入。
配置如下:
chainWebpack: (config: Config) => {
config.module
.rule('images')
.use('lqip-loader')
.loader('lqip-loader')
.before('url-loader');
return config;
},
使用方法
当直接 import 一张图片时,会有三个参数 src
、preSrc
和 palette
(可选)
接口签名
interface LqipImage {
src: string;
preSrc: string;
palette?: string[];
}
简单测试:
import banner from './images/banner.jpg';
console.log(banner.preSrc);
// 输出: "data:image/jpeg;base64,/9j/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhY....
// banner 将具有调色板属性(在配置项中开启 palette: true ),数组将从最主要的颜色排序到最少
console.log(banner.palette)
// 输出: [ '#628792', '#bed4d5', '#5d4340', '#ba454d', '#c5dce4', '#551f24' ]
console.log(banner.src) // 原图片 url
案例
由于 import 之后的图片结构做了变动,因此个人建议自行在已有的图片组件基础上封装一个集成 lqip
输出物的图片组件。
封装的思想很简单,就是对传入的 src 做个判断,如果是字符串,返回原来你自己使用的图片组件,如果是个对象,那么自行处理 src
和 preSrc
的相关逻辑。
案例:本人选择搭配 react-simple-img 使用,这个组件集成了懒加载、图片占位符、响应式加载图片、响应式尺寸等能力(预览 Demo 见下方)。
我自行封装的 LazyImage
如下:
import { SimpleImg } from 'react-simple-img';
import React, { FC } from 'react';
interface LazyImageProps {
src: AdaptiveImage;
height?: number | string;
width?: number | string;
placeholder?: string | boolean;
className?: string;
alt?: string;
sizes?: string;
}
const LazyImage: FC<LazyImageProps> = ({
src,
height,
width,
placeholder,
className,
alt,
sizes,
}) => {
if (typeof src === 'string') {
return (
<SimpleImg
placeholder={placeholder}
src={src}
sizes={sizes}
alt={alt}
height={height}
width={width}
className={className}
/>
);
}
return (
<SimpleImg
placeholder={src.preSrc}
src={src.src}
alt={alt}
height={height ? height : undefined}
width={width}
className={className}
/>
);
};
export default LazyImage;
我原本使用 SimgleImg 的代码如下:
<SimpleImg
src={img}
width={width}
placeholder={false} // 不使用占位符
height={imageHeight ? imageHeight : height}
/>
使用了 lqip
之后,直接无痛切换到自己封装的 LazyImage
<LazyImage
src={img}
width={width}
height={imageHeight ? imageHeight : height}
/>