前端性能优化-图片处理
丰富的网页元素,图片肯定少不了,围绕图片的优化也有很多对应的方法。
# 图片优化常用手段
- 图片懒加载,在页面上的未可视区域可以添加一个滚动条事件,判断图片位置与浏览器顶端 的距离与页面的距离,如果前者小于后者,优先加载。
// 实现图片懒加载其核心的思想就是将img的src属性先使用一张本地占位符,或者为空。
//然后真实的图片路径再定义一个data-set属性存起来,待达到一定条件的时将data-img的属性值赋给src
import {loadImage} from './load';
// HTML: <img src="path/to/demo.gif" lazy-original="path/to/img.gif" class="img-lazyload j-lazyload" />
// 加载可视区域的图片
export const lazyLoadImage = () => {
let $domLazyImages = $('.j-lazyload').toArray();
let height = $(window).height();
$domLazyImages.map(function (item, index) {
let $dom = $(item);
let {top, bottom} = $dom[0].getBoundingClientRect();
// 正在加载中、已经加载、不在可视区则不重复加载
if ($dom.hasClass('img-lazyloading') || $dom.hasClass('img-lazyloaded') || top > height || bottom <= 0) {
return false;
}
$dom.addClass('img-lazyloading');
let imageSrc = $dom.attr('lazy-original');
loadImage([imageSrc]).then(() => {
$dom.attr('src', imageSrc);
$dom.removeClass('j-lazyload').removeClass('img-lazyloading').addClass('img-lazyloaded');
});
});
};
# vue 指令封装
// 引入polyfill,解决兼容性问题
import 'intersection-observer';
IntersectionObserver.prototype['THROTTLE_TIMEOUT'] = 300;
const DefaultLoadingImage = '默认loading图片'
export default class LazyLoadImage {
_observer: IntersectionObserver | null;
_loadingImage: string;
constructor(option: object = {}) {
this._observer = null;
// @ts-ignore
this._loadingImage = option.loading || DefaultLoadingImage;
this.init();
}
init() {
this._observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
// 触发进入视窗条件,替换真正的图片链接到src属性上
if (entry.isIntersecting) {
// @ts-ignore
const url = entry.target.getAttribute('data-src');
// @ts-ignore
entry.target.setAttribute('src', url);
entry.target.setAttribute('data-src', '');
// 替换真正的线上地址后,取消对该元素的观察
this._observer && this._observer.unobserve(entry.target);
}
})
}, {
root: null,
rootMargin: "500px 200px 1000px 200px", // 扩大视窗范围,提前加载
threshold: 0.1
})
}
// 让每个img标签自行调用add方法,把自己添加到观察者队列中
add(entry: any) {
this._observer && this._observer.observe(entry.el);
}
}
// 全局只实例化一个类,实例执行init方法自己创建观察者队列
const lazyload = new LazyLoadImage();
// 让每个img标签自行调用add方法,把自己添加到观察者队列中
// 用法: <img v-lazy="图片地址" />
Vue.directive('lazy', {
bind(el, binding) {
el.setAttribute('data-src', binding.value);
el.setAttribute('src', lazyload._loadingImage);
lazyload.add({el: el, val: binding.value});
}
})
- 如果为幻灯片、相册等,可以使用图片预加载技术,将当前展示图片的前一张和后一张优先下载。
- 如果图片为css 图片,可以使用CSSsprite,SVGsprite,Iconfont、Base64 等技术。
- 如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图以提高用户体验。 或者使用响应式图片的优点是浏览器能够根据屏幕大小自动加载合适的图片。 可以使用picture标签
<picture>
<source srcset="banner_w1000.jpg" media="(min-width: 801px)">
<source srcset="banner_w800.jpg" media="(max-width: 800px)">
<img src="banner_w800.jpg" alt="">
</picture>
或者使用媒体查询
@media (min-width: 769px) {
.bg {
background-image: url(bg1080.jpg);
}
}
@media (max-width: 768px) {
.bg {
background-image: url(bg768.jpg);
}
}
- 如果图片展示区域小于图片的真实大小,则因在服务器端根据业务需要先行进行图片压缩, 图片压缩后大小与展示一致。
- css样式代替图片,例如:半透明、圆角、阴影、高光、渐变等。这些效果主流的浏览器都能够完美支持。
- 使用SVG或webp格式,对于绝大多数图案、图标 等,矢量图更小,且可缩放而无需生成多套图。
- 适当压缩图片 JPG 格式的图片,100% 的质量和 90% 质量的通常看不出来区别,尤其是用来当背景图的时候。当然还是得考虑具体场景需求 通用可使用webpack自动化,也可以自己直接在线压缩
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use:[
{
loader: 'url-loader',
options: {
limit: 10000, /* 图片大小小于1000字节限制时会自动转成 base64 码引用*/
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
/*对图片进行压缩*/
{
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true,
}
}
]
}