自己实现vue懒加载
实现 Vue 懒加载的基本思路
懒加载(Lazy Loading)的核心思想是按需加载资源,通常在 Vue 中用于延迟加载组件或图片。以下是两种常见的实现方式:
组件懒加载
Vue 结合 Webpack 的动态导入(Dynamic Import)实现组件懒加载:
// 静态导入(非懒加载)
import StaticComponent from './StaticComponent.vue'
// 动态导入(懒加载)
const LazyComponent = () => import('./LazyComponent.vue')
export default {
components: {
StaticComponent,
LazyComponent
}
}
动态导入会返回一个 Promise,Webpack 会自动将动态导入的组件拆分为单独的 chunk,仅在需要时加载。
图片懒加载
实现图片懒加载需要监听元素是否进入视口:

// 自定义指令实现
Vue.directive('lazy', {
inserted: (el, binding) => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
el.src = binding.value
observer.unobserve(el)
}
})
})
observer.observe(el)
}
})
// 使用方式
<img v-lazy="'path/to/image.jpg'" alt="Lazy Image">
优化懒加载体验
添加加载状态和错误处理:
Vue.directive('lazy', {
inserted: (el, binding) => {
el.src = 'placeholder.jpg' // 占位图
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = new Image()
img.src = binding.value
img.onload = () => {
el.src = binding.value
}
img.onerror = () => {
el.src = 'error.jpg' // 错误处理
}
observer.unobserve(el)
}
})
})
observer.observe(el)
}
})
浏览器兼容性处理
对于不支持 IntersectionObserver 的浏览器:

const lazyLoad = (el) => {
const rect = el.getBoundingClientRect()
return (
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.left <= (window.innerWidth || document.documentElement.clientWidth)
)
}
Vue.directive('lazy', {
inserted: function(el, binding) {
function load() {
if (lazyLoad(el)) {
el.src = binding.value
window.removeEventListener('scroll', load)
}
}
window.addEventListener('scroll', load)
load()
}
})
性能优化建议
-
设置合适的 rootMargin 扩大触发范围:
new IntersectionObserver(callback, { rootMargin: '200px' }) -
对大量图片使用节流:
let ticking = false window.addEventListener('scroll', () => { if (!ticking) { window.requestAnimationFrame(() => { loadImages() ticking = false }) ticking = true } }) -
预加载即将进入视口的资源:
const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting || entry.boundingClientRect.top < 300) { // 加载逻辑 } }) }, { rootMargin: '300px' })
以上实现方式可以根据项目需求进行组合和调整,核心思想都是延迟资源的加载时机直到真正需要时。






