优化
懒加载和预加载
懒加载也叫做延迟加载、按需加载
,指的是长网页中延迟加载图片数据。懒加载适用于图片较多,页面较长的页面场景中。
预加载指的是将所需的资源提前请求
加载到本地,这样后面在需要用到时就直接从缓存取资源。通过预加载能够减少用户的等待时间,提高用户的体验。
路由懒加载
路由懒加载就是只加载点击的那个模块,按需加载路由对应的资源
原理:利用了 ES6 的 import()函数动态地加载模块。将路由相关的组件,不再直接导入,而是改写成异步组件的写法,只有当函数被调用的时候,才去加载对应的组件内容。
这样可以避免在初次加载应用时加载过多的组件代码,从而提高应用的性能和体验。
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{ path: '/login', component: () => import('@/views/login/index.vue') },
{ path: '/home', component: () => import('@/views/home/home.vue') }
]
export default router
import()函数:一般来说,当在代码中使用 import()函数时,打包攻击会将对应的模块代码单独分割出来,并生成一个独立的 chunk(代码块)文件。这些 chunk 可以是 JS, CSS 或者其他资源类型,根据具体的配置和需求进行优化。
当页面加载时,只会加载当前页面所需的主 chunk 文件,而其他 chunk 文件则会在需要时在进行异步加载。
当 import()函数被调用时,相应的 chunk 文件会被下载并解析,从而完成加载模块的过程
实现:路由懒加载一般是由前端框架或其他库来实现的,打包工具会根据配置来生成对应的 chunk 文件,因此,路由懒加载既涉及前端框架或库的使用,也与打包工具和优化密切相关。
图片懒加载
对于图片量比较大的首页,用户打开页面后,只需要呈现出屏幕可视区域内的图片,当用户滑动页面时,再去加载出现在屏幕内的图片,以优化图片的加载效果
实现原理
图片的加载是由 src 引起的,当对 src 赋值时,浏览器就会请求图片资源。
由于浏览器会自动对页面中的 img 标签的 src 属性发送请求并下载图片,可以通过 html5 自定义属性 data-xxx 先暂存 src 的值,然后在图片出现在屏幕可视区域的时候,再将 data-xxx 的值重新赋值到 img 的 src 属性即可
懒加载的实现重点在于确定用户需要加载哪张图片,在浏览器中,可视区域的资源就是用户需要的资源。
所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可
实现 1:浏览器原生支持
element 的 loading="lazy"属性
<img src="./example.jpg" loading="lazy" alt="loading lazy">
loading 属性可用于 iframe 标签和 img 标签;
eager
默认值:当 loading 属性的默认值为 eager,即立即请求资源,即当你不设置 loading='lazy'时,或者 loading="无效值"时,均代表立即请求当前资源;lazy
:代表将延迟加载当前 element,但如果页面禁止了 JavaScript 的运行,则也不会生效,这是浏览器的一种反追踪措施;
实现 2:监听图片元素是否可见(IntersectionObserver API)
IntersectionObserver API
,可以自动"观察"元素是否可见。由于可见(visible)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做 交叉观察器
。
IntersectionObserver
在懒加载、虚拟滚动、曝光统计、上拉刷新等场景中,均能提供高效的解决方案。因为传统的观察元素是否可见方案,都离不开Element.getBoundingClientRect
等 DOM 方法,而这些方法均运行在浏览器主线程,一旦方案设计有缺陷,去频繁的触发调用,便会造成一定的性能问题。
<img data-src="image.jpg" alt="test image" />
<script type="text/javascript">
const config = {
rootMargin: "0px 0px 50px 0px",
threshold: 0,
};
const preloadImage = (imagEl) => {
if (imagEl.getAttribute("src") !== imagEl.getAttribute("data-src")) {
imagEl.src = imagEl.getAttribute("data-src");
}
};
let observer = new intersectionObserver(function (entries, self) {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// 将 data-src 改到 src
preloadImage(entry.target);
// 停止对它监听
self.unobserve(entry.target);
}
});
}, config);
const imgs = document.querySelectorAll("[data-src]");
imgs.forEach((img) => {
observer.observe(img);
});
</script>
实现 3:监听 scroll 事件
<body>
<style>
img {
display: block;
margin-bottom: 50px;
height: 200px;
}
</style>
<img src="images/placeholder.jpg" data-src="images/1.png" />
<img src="images/placeholder.jpg" data-src="images/2.png" />
<img src="images/placeholder.jpg" data-src="images/3.png" />
<img src="images/placeholder.jpg" data-src="images/4.png" />
<img src="images/placeholder.jpg" data-src="images/5.png" />
<img src="images/placeholder.jpg" data-src="images/6.png" />
<img src="images/placeholder.jpg" data-src="images/7.png" />
<img src="images/placeholder.jpg" data-src="images/8.png" />
<img src="images/placeholder.jpg" data-src="images/9.png" />
<img src="images/placeholder.jpg" data-src="images/10.png" />
<img src="images/placeholder.jpg" data-src="images/11.png" />
<img src="images/placeholder.jpg" data-src="images/12.png" />
<script>
function throttle(fn, delay, atleast) {
var timeout = null;
var startTime = new Date();
return function () {
var curTime = new Date();
clearTimeout(timeout);
if (curTime - startTime >= atleast) {
fn();
startTime = curTime;
} else {
timeout = setTimeout(fn, delay);
}
};
}
function lazyload() {
var images = document.querySelectorAll("[data-src]");
var len = images.length;
var n = 0; //存储图片加载到的位置,避免每次都从第一张图片开始遍历
return function () {
var seeHeight = document.documentElement.clientHeight;
var scrollTop =
document.documentElement.scrollTop || document.body.scrollTop;
for (var i = n; i < len; i++) {
if (images[i].offsetTop < seeHeight + scrollTop) {
if (
images[i].getAttribute("src") !==
images[i].getAttribute("data-src")
) {
images[i].src = images[i].getAttribute("data-src");
}
n = n + 1;
}
}
};
}
var loadImages = lazyload();
loadImages(); //初始化首页的页面图片
// window.addEventListener('scroll', loadImages, false); //会被高频触发,这非常影响浏览器的性能
window.addEventListener("scroll", throttle(loadImages, 500, 1000), false); //设置500ms 的延迟,和 1000ms 的间隔 避免高频防抖
</script>
</body>