vue懒加载

文章目录


什么是懒加载

懒加载,也称为延迟加载,是一种将资源(如图片、组件、代码等)推迟到需要的时候再加载的策略。在 Vue 中,懒加载通常涉及到组件和图片的加载。
优点:

  1. 减少初始加载时间:只加载当前可见内容,减少首屏资源量
  2. 按需加载避免浪费:减少了带宽浪费缓解服务器压力

组件懒加载

1.异步组件函数实现(推荐)

defineAsyncComponent

typescript 复制代码
import { h, defineAsyncComponent } from 'vue';
//简单
const async1 = defineAsyncComponent(() => import('./components/MyComponent.vue'))

const async2 = defineAsyncComponent({
  loader: //必须是一个promise类型(动态import()就返回promise对象)
   ,
   loadingComponent: {//异步执行未完成时展示组件(模拟一个组件,组件调用时会调用render函数)
   //h虚拟dom函数用于创建虚拟dom节点(h(tag, props, children))
    render() {
      return h('div', '加载中')
    }
  },
  errorComponent: {//超出timeout后展示
    render() {
      return h('div', '加载失败')
    }
  },
  delay: 200,//延迟时间结束后展示加载中
  timeout: 3000
  })
  //使用(对应vue文件)
  	<async1></async1>
    <async2></async2>
  

此处没有对async进行渲染控制,也就是直接触发渲染,进行组件获取,

仅实现了代码分割

只需要给组件标签加上v-if渲染条件,即实现了按需加载(当组件渲染时才会执行对应的函数)实现真正的懒加载

内置component组件自己实现

组件对象不能用响应式对象来接收

一般使用shallowRef()的实例对象避免对组件对象的响应式化

原因(组件对象包含大量的vue的静态属性和方法等执行中从不改变 故不应使用响应式)

如下应该初始化const loadedComponent=shallowRef()

而对 shallowRef对象接收后对.value 进行响应式追踪

也是为何后续赋值loadedComponent.value = module.default的原因

module.default是因为<script setup>块会被编译为export default(modulde是导入的组件)

来自vue2 的设计

html 复制代码
<component 
        :is="loadedComponent" 
        v-bind="$attrs"
      />

:is渲染对应属性值的组件,若该值不是组件不渲染,也就是可以修改值实现动态组件
v-bind"$attrs"将父组件的属性 不属于本组件props部分的传给动态组件

在下例中

app.vue->中间层->被导入的组件

传了name1和2 (name2被拦截) 默认值是3

故展示1和3

举例

直接导入组件

typescript 复制代码
//studyC.vue(可传入一个组件)
<template>
  <div>
    <component
    :is="will"
    v-bind="$attrs"></component>
  </div>
</template>

<script setup lang="ts">
import {ref,onMounted,shallowRef} from 'vue'

interface Props {
//html不分大小写用-模拟小驼峰命名
    willLoader:Promise<any>,//import()返回的是promise类型
    //会对应will-loader属性
    name2:number//去掉这里定义 展示就会是1,2
}
const props=defineProps<Props>()
//响应式will用于储存提取出的组件
const will=shallowRef()
//组件挂载时直接执行  相当于立即执行
onMounted(async () => {
  try {
  //promise异步 解析后的default属性就是组件
    const module = await props.willLoader
    will.value = module.default
  } catch (error) {
    console.error('组件加载失败:', error)
  }
})
</script>



//被导入的组件
<template>
  <div>{{ name1 }}</div>
  <div>{{ name2 }}</div>
</template>

<script setup lang="ts">
interface Props{
name1:number
name2?:number
}
const props=withDefaults(defineProps<Props>(),{
    name2:3
})
</script>

<style scoped>

</style>

//使用app.vue
<studyC :name1="1" :name2="2" :will-loader="import('./components/willloader.vue')"></studyC>
//import()先编译  也就是可以使用相对位置,
//此处直接import并不是懒加载,在第一次就会直接加载
//展示1,3
//2被中间层拦截了

利用此实现组件懒加载

  1. 改写导入方式
typescript 复制代码
<studyC :name1="1" :name2="2" :will-loader="()=>import('./components/willloader.vue')">
  1. 需要时调用此函数(自行加入条件)

如下改成利用按钮控制触发条件的懒加载

typescript 复制代码
<template>
    <div class="lazy-component-wrapper">
      <!-- 按钮触发加载 -->
      <button 
        @click="loadComponent" 
        :disabled="loading || loaded"
      >
        {{ getButtonText }}
      </button>
      
      <!-- 加载状态 -->
      <div v-if="loading">
        组件加载中...
      </div>
      
      <!-- 渲染加载的组件 -->
      <component 
        :is="loadedComponent" 
        v-if="loadedComponent && !loading"
        v-bind="$attrs"
      />
    </div>
  </template>
  
  <script setup lang="ts">
  import { ref, computed,shallowRef } from 'vue'
  
  interface Props {
    // 接收组件导入函数
    componentLoader: () => Promise<any>
    //传入方式:component-loader="() => import('./components/MyComponent.vue')
    buttonText?: string
    loadingText?: string
  }
  
  const props = withDefaults(defineProps<Props>(), {
    buttonText: '加载组件',
    loadingText: '加载中...'
  })
  
  // 响应式数据
  const loading = ref(false)
  const loaded = ref(false)
  const loadedComponent = shallowRef()
  
  const getButtonText = computed(() => {
    if (loading.value) return props.loadingText
    if (loaded.value) return '组件已加载'
    return props.buttonText
  })
  
  // 加载组件
  const loadComponent = async () => {
    if (loading.value || loaded.value) return
    
    loading.value = true
    
    try {
      // 真正开始导入组件
      const module = await props.componentLoader()
      loadedComponent.value = module.default
      loaded.value = true
    } catch (error) {
      console.error('组件加载失败:', error)
    } finally {
      loading.value = false
    }
  }

  defineExpose({
  loadedComponent,
  loadComponent,
  getButtonText
  })
  </script>
//使用
<buttonlazy :name1="1" :name2="2" :component-loader="() => import('./components/willloader.vue')"></buttonlazy>
//此处没有拦截name1和name2  故展示 1,2

图片懒加载

方案一:

利用了src被img识别时才导入的效果实现懒加载

一般使用自定义指令实现 这里用组件模拟

typescript 复制代码
//myimg
<template>
    <div class="lazy-img">
      <button 
        v-if="!loaded" 
        @click="loadImage" 
        :disabled="loading"
      >
        {{ loading ? '加载中...' : '点击加载图片' }}
      </button>
      
      <img 
        v-else 
        :src="props.src" 
        :alt="props.alt" 
      />
    </div>
  </template>
  
  <script setup lang="ts">
  import { ref } from 'vue'
  
  // 定义 props
  interface Props {
    src: string
    alt?: string
  }
  
  const props = withDefaults(defineProps<Props>(), {
    src: '',
    alt: '图片'
  })
  
  // 响应式数据
  const loaded = ref(false)
  const loading = ref(false)
  
  // 加载图片
  const loadImage = async () => {
    if (loading.value || loaded.value) return
    
    loading.value = true
    
    // 模拟网络延迟
    await new Promise(resolve => setTimeout(resolve, 500))
    
    loaded.value = true
    loading.value = false
  }
  </script>
//使用
<myimg src="/src/img/120baf1265ee54cb9cb1fa17c2dcae33.png"></myimg>
//此处src是字符串   不会自动对应   

更多使用Vanilla Lazyload或lozad库实现

问题1
这是懒加载吗

typescript 复制代码
//使用
	<async1></async1>
//定义
const async1 = defineAsyncComponent(() => import('./components/MyComponent.vue'))

问题2

为何组件对象要使用shallowRef()实例对象接收而不使用ref()实例对象

相关推荐
国家不保护废物3 小时前
手写 Vue Router,揭秘路由背后的魔法!🔮
前端·vue.js
菜鸟‍4 小时前
【前端学习】仿Deepseek官网AI聊天网站React
前端·学习·react.js
小光学长4 小时前
基于Vue的保护动物信息管理系统r7zl6b88 (程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库·vue.js
huangql5205 小时前
截图功能技术详解:从原理到实现的完整指南
前端·html5
长空任鸟飞_阿康5 小时前
Node.js 核心模块详解:fs 模块原理与应用
前端·人工智能·ai·node.js
这儿有一堆花5 小时前
网站链接重定向原理
前端
麦麦大数据5 小时前
F029 vue游戏推荐大数据可视化系统vue+flask+mysql|steam游戏平台可视化
vue.js·游戏·信息可视化·flask·推荐算法·游戏推荐
cecyci5 小时前
如何实现AI聊天机器人的打字机效果?
前端·javascript
IT_陈寒5 小时前
Vite 5个隐藏技巧让你的项目构建速度提升50%,第3个太香了!
前端·人工智能·后端