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()实例对象

相关推荐
Amewin11 分钟前
在vue3+uniapp+vite中挂载全局属性方法
javascript·vue.js·uni-app
玖釉-12 分钟前
用 Vue + DeepSeek 打造一个智能聊天网站(完整前后端项目开源)
前端·javascript·vue.js
zhangyao9403301 小时前
关于js导入Excel时,Excel的(年/月/日)日期是五位数字的问题。以及对Excel日期存在的错误的分析和处理。
开发语言·javascript·excel
骑驴看星星a1 小时前
【Three.js--manual script】4.光照
android·开发语言·javascript
devincob7 小时前
js原生、vue导出、react导出、axios ( post请求方式)跨平台导出下载四种方式的demo
javascript·vue.js·react.js
编程社区管理员7 小时前
React 发送短信验证码和验证码校验功能组件
前端·javascript·react.js
葡萄城技术团队7 小时前
迎接下一代 React 框架:Next.js 16 核心能力解读
javascript·spring·react.js
全马必破三7 小时前
React“组件即函数”
前端·javascript·react.js
三思而后行,慎承诺7 小时前
React 底层原理
前端·react.js·前端框架
座山雕~7 小时前
html 和css基础常用的标签和样式
前端·css·html