news 2026/9/3 2:03:36

Vue—— Vue3 懒加载与预加载策略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue—— Vue3 懒加载与预加载策略

背景问题:
需要优化页面加载性能。

方案思考:
使用懒加载和预加载策略来平衡性能和用户体验。

具体实现:
图片懒加载指令:

// directives/lazy-image.jsexportdefault{mounted(el,binding){// 创建 Intersection Observerconstobserver=newIntersectionObserver((entries)=>{entries.forEach(entry=>{if(entry.isIntersecting){// 图片进入视口,加载真实图片constimg=newImage()img.onload=()=>{el.src=binding.value el.classList.remove('lazy-img--loading')el.classList.add('lazy-img--loaded')observer.unobserve(el)}img.src=binding.value// 添加加载状态样式el.classList.add('lazy-img--loading')el.src='data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iI2NjYyIvPjwvc3ZnPg=='// 占位图}})})observer.observe(el)},updated(el,binding){// 当绑定值变化时更新if(binding.value!==binding.oldValue){el.src='data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iI2NjYyIvPjwvc3ZnPg=='el.classList.remove('lazy-img--loaded')constobserver=newIntersectionObserver((entries)=>{entries.forEach(entry=>{if(entry.isIntersecting){constimg=newImage()img.onload=()=>{el.src=binding.value el.classList.remove('lazy-img--loading')el.classList.add('lazy-img--loaded')observer.unobserve(el)}img.src=binding.value el.classList.add('lazy-img--loading')}})})observer.observe(el)}}}

组件懒加载:

<!-- components/LazyComponent.vue --> <template> <div class="lazy-component"> <div v-if="loading" class="loading-placeholder"> <el-skeleton :rows="5" /> </div> <component v-else :is="dynamicComponent" v-bind="componentProps" /> </div> </template> <script setup> import { ref, defineAsyncComponent } from 'vue' const props = defineProps({ componentPath: { type: String, required: true }, componentProps: { type: Object, default: () => ({}) } }) const loading = ref(true) const dynamicComponent = ref(null) // 动态加载组件 const loadComponent = async () => { try { // 使用 defineAsyncComponent 进行懒加载 dynamicComponent.value = defineAsyncComponent({ loader: () => import(`@/components/${props.componentPath}.vue`), loadingComponent: null, // 我们自己处理加载状态 errorComponent: null, // 我们自己处理错误 delay: 200, // 延迟显示加载状态 timeout: 3000 // 超时时间 }) } catch (error) { console.error('组件加载失败:', error) } finally { loading.value = false } } loadComponent() </script> <style scoped> .loading-placeholder { padding: 20px; } </style>

预加载策略:

// utils/prefetch.js// 预加载工具类exportclassPrefetchUtil{constructor(){this.prefetchedResources=newSet()}// 预加载脚本asyncprefetchScript(src){if(this.prefetchedResources.has(src)){return}returnnewPromise((resolve,reject)=>{constlink=document.createElement('link')link.rel='prefetch'link.href=src link.onload=resolve link.onerror=reject document.head.appendChild(link)this.prefetchedResources.add(src)})}// 预加载组件asyncprefetchComponent(componentPath){if(this.prefetchedResources.has(componentPath)){return}try{awaitimport(`@/components/${componentPath}.vue`)this.prefetchedResources.add(componentPath)}catch(error){console.error('预加载组件失败:',error)}}// 预加载路由asyncprefetchRoute(routeName){// 这里可以根据路由名称预加载对应组件constrouteModule=awaitimport(`@/views/${routeName}.vue`)returnrouteModule}// 根据用户行为预测预加载predictAndPrefetch(routes){// 基于用户历史行为或路由关系预测可能访问的页面routes.forEach(route=>{setTimeout(()=>{this.prefetchRoute(route)},2000)// 延迟预加载,避免影响当前页面性能})}// 清除预加载缓存clearCache(){this.prefetchedResources.clear()}}// 创建全局预加载实例exportconstprefetchUtil=newPrefetchUtil()

虚拟滚动实现:

<!-- components/VirtualList.vue --> <template> <div ref="containerRef" class="virtual-list" :style="{ height: containerHeight + 'px' }" @scroll="handleScroll" > <div :style="{ height: totalHeight + 'px' }" class="virtual-list__spacer"> <div v-for="item in visibleItems" :key="item.id" :style="{ height: itemHeight + 'px', transform: `translateY(${item.index * itemHeight}px)` }" class="virtual-list__item" > <slot :item="item" :index="item.index" /> </div> </div> </div> </template> <script setup> import { ref, computed, onMounted, onUnmounted } from 'vue' const props = defineProps({ items: { type: Array, required: true }, itemHeight: { type: Number, default: 50 }, containerHeight: { type: Number, default: 400 } }) const containerRef = ref(null) const scrollTop = ref(0) // 计算可见项 const visibleRange = computed(() => { const startIndex = Math.floor(scrollTop.value / props.itemHeight) const visibleCount = Math.ceil(props.containerHeight / props.itemHeight) const endIndex = Math.min(startIndex + visibleCount + 5, props.items.length) // 多渲染几个以防万一 return { start: Math.max(0, startIndex), end: endIndex } }) // 可见项数据 const visibleItems = computed(() => { return props.items .slice(visibleRange.value.start, visibleRange.value.end) .map((item, index) => ({ ...item, index: visibleRange.value.start + index })) }) // 总高度 const totalHeight = computed(() => props.items.length * props.itemHeight) // 处理滚动 const handleScroll = () => { scrollTop.value = containerRef.value.scrollTop } onMounted(() => { scrollTop.value = containerRef.value.scrollTop }) </script> <style scoped> .virtual-list { overflow-y: auto; position: relative; } .virtual-list__spacer { position: relative; width: 100%; } .virtual-list__item { position: absolute; left: 0; right: 0; display: flex; align-items: center; padding: 0 16px; border-bottom: 1px solid #eee; } </style>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 14:38:29

Atlas-OS环境下MSI安装包2203错误的全面诊断与修复指南

Atlas-OS环境下MSI安装包2203错误的全面诊断与修复指南 【免费下载链接】Atlas &#x1f680; An open and lightweight modification to Windows, designed to optimize performance, privacy and security. 项目地址: https://gitcode.com/GitHub_Trending/atlas1/Atlas …

作者头像 李华
网站建设 2026/9/2 22:22:26

Base2048编码:突破Twitter数据传输限制的终极指南

Base2048编码&#xff1a;突破Twitter数据传输限制的终极指南 【免费下载链接】base2048 Binary encoding optimised for Twitter 项目地址: https://gitcode.com/gh_mirrors/ba/base2048 &#x1f680; 你是否曾经想要在一条简单的Twitter消息中传输更多的数据&#xf…

作者头像 李华
网站建设 2026/9/2 10:46:30

Mindustry终极指南:掌握星际自动化防御的艺术

Mindustry终极指南&#xff1a;掌握星际自动化防御的艺术 【免费下载链接】Mindustry The automation tower defense RTS 项目地址: https://gitcode.com/GitHub_Trending/min/Mindustry Mindustry作为一款融合了塔防策略、资源自动化管理和实时战略的独特开源游戏&…

作者头像 李华
网站建设 2026/8/27 10:43:51

MinerU-1.2B性能测试:不同硬件平台对比

MinerU-1.2B性能测试&#xff1a;不同硬件平台对比 1. 引言 随着企业数字化转型的加速&#xff0c;智能文档理解&#xff08;Document Intelligence&#xff09;技术在金融、教育、法律和科研等领域的应用日益广泛。传统的OCR工具虽然能够实现基础的文字识别&#xff0c;但在…

作者头像 李华
网站建设 2026/9/3 1:49:31

163MusicLyrics:音乐歌词提取的完美解决方案

163MusicLyrics&#xff1a;音乐歌词提取的完美解决方案 【免费下载链接】163MusicLyrics Windows 云音乐歌词获取【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 你是否曾为找不到心爱歌曲的完整歌词而烦恼&#xff1f;是否在音…

作者头像 李华
网站建设 2026/9/3 1:45:12

Kronos金融AI预测模型终极指南:从零构建量化交易系统

Kronos金融AI预测模型终极指南&#xff1a;从零构建量化交易系统 【免费下载链接】Kronos Kronos: A Foundation Model for the Language of Financial Markets 项目地址: https://gitcode.com/GitHub_Trending/kronos14/Kronos Kronos作为金融市场的"语言模型&quo…

作者头像 李华