让图片的加载更加优雅
- 无框架限制 - 基于 Web Components
- 懒加载 - 基于 Intersection Observer API
- 支持加载远程链接
- 模式
- blurhash - 模糊算法生成占位图
- lqip - 以缩略 base64 图为过渡
- sqip - 以 svg 轮廓为过渡,可自定义轮廓,滤镜
- cucoloris - 以剪影为过渡,可自定义颜色,背景色
- draw - 以动态画笔为过渡,可自定义画笔颜色
- 支持 - jpg,jpeg,png,gif,webp
- 自定义过渡
- 集成
你可能会看到图片首次加载之后,再次加载几乎看不到过渡动画,这是有意为之的,我们解决的是图片加载过程中的留白,但通常图片访问后会被浏览器缓存,再次访问就不需要加载过渡动画来浪费时间。如果你的图片没有使用缓存策略,依旧会加载过渡动画。
npm install magic-img
// magic = blurhash|lqip|sqip|cucoloris|draw
import img from './home.png?magic=lqip'
// 可拼接参数
import img from './home.png?magic=sqip&numberOfPrimitives=100&blur=0'
// 加载远程链接
import img from 'magic-img@https://cdn.pixabay.com/photo/2013/07/18/20/26/sea-164989__480.jpg?magic=lqip'
使用 Web Component 好处是无技术栈限制,缺点是 ssr 不友好。
// main.js
import installMagicImg from 'magic-img'
import 'magic-img/css'
installMagicImg()
// vue
<magic-img :src='img'>
// react
<magic-img src={ img }>
// ... 其他技术栈
针对 SSR 需求,可以不使用 web components,有以下框架集成(持续增加中。。。)。
import 'magic-img/css'
import MagicImg from 'magic-img/vue2'
// import MagicImg from 'magic-img/vue3' // vue3
Vue.use(MagicImg)
<MagicImg :src='img' />
import 'magic-img/css'
import MagicImg from 'magic-img/react'
<MagicImg src={img} />
// vite.config.js
import magicImg from 'magic-img/vite';
export default {
plugins: [
magicImg(/* options */)
]
}
// webpack.config.js
const magicImg = require('magic-img/webpack').default;
module.exports = {
plugins: [
magicImg(/* options */)
]
}
- blurhash
- w (number) - 缩略图宽度(指的是压缩的宽度值,不是实际展示) (default: 20)
- h (number) - 缩略图高度
- componentX (number) (default: 4)
- componentY (number) (default: 4)
- punch (number) - 对比度
- hash (string) - 自定义 hash,默认取自图片
- lqip
- w (number) - 缩略图宽度 (default: 20)
- h (number) - 缩略图高度
- sqip
- numberOfPrimitives (number) - 生成的轮廓数量 (default: 20)
- blur (number) - 滤镜 (default: 2)
- mode (number) - 轮廓模式 (default: 0) 0=combo, 1=triangle, 2=rect, 3=ellipse, 4=circle, 5=rotatedrect, 6=beziers, 7=rotatedellipse, 8=polygon
- cucoloris
- background (string) - 背景色 (default: '#fff')
- color (string) - c7d4d8 (default: '#c7d4d8')
- threshold (number) - 阈值 (default: 120)
- draw
- w (number) - 缩略图宽度 (default: 400)
- h (number) - 缩略图高度
// vite.config.js
import magicImg from 'magic-img/vite';
export default {
plugins: [
magicImg({
sqip: {
numberOfPrimitives: 100,
blur: 0,
}
})
]
}
根据不同状态你可以自定义过渡效果
<magic-img>
<!-- 占位元素,可能是 img,svg -->
<placeholder class='magic-placeholder' />
<!-- 最终展示图片 -->
<target class='magic-target' />
</magic-img>
- default - 你可以默认一些样式
- from - 当元素出现在视窗内,此时也会加载真正的图片 placeholder,target 会被设置属性 status=from
- to - 真正的图片加载完毕 placeholder,target 会被设置属性 status=to
<magic-img src='xxx' class='my-style'>
.my-style .magic-placeholder {
filter: blur(10px)
}
.my-style .magic-target[status=from] {
border: 1px solid;
}
.my-style .magic-target[status=to] {
opacity: 1;
filter: grayscale(1);
transition: all 4s;
}
在 vue 中,custom element 需要注册
Vue.config.ignoredElements = [
'magic-img',
]
// vite.config.js
import vue from '@vitejs/plugin-vue'
export default {
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.includes('magic-img')
}
}
})
]
}
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => ({
...options,
compilerOptions: {
// treat any tag that starts with ion- as custom elements
isCustomElement: tag => tag.startsWith('magic-img')
}
}))
}
}
// 与 vue-cli loader 配置冲突,需要处理
chainWebpack(config) {
config.module.rule('images').clear()
config.module.rule('magic-img')
.test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
.use('file-loader')
.loader('file-loader')
.options({
'name': 'img/[name].[hash:8][ext]'
})
}