vue异步组件与组件懒加载(解决import不能导入变量字符串的路径问题)

本文探讨了在Vue项目中实现动态路由菜单的配置方法,特别是在使用webpack时如何正确处理异步加载的问题。文章分析了错误的import用法,并提供了两种解决方案:利用字符串模板和自定义懒加载函数,以实现组件的按需加载。

在写项目的时候,需要动态配置路由菜单,所有的菜单都是通过配置生成的,这就意味着菜单的路径(在vue开发项目里面就是一个字符串的路径)需要异步加载进去,但是由于对webpack的import不是很熟悉,所以就有一下的坑需要填了

错误的原因分析

_import.js
module.exports = file => () => import(file)

在这里插入图片描述

但是这种方法错误的原因是:

webpack 编译es6 动态引入 import() 时不能传入变量,例如dir =’path/to/my/file.js’ ; import(dir) , 而要传入字符串 import(‘path/to/my/file.js’),这是因为webpack的现在的实现方式不能实现完全动态。

解决方案一:

可以通过字符串模板来提供部分信息给webpack;例如import(./path/${myFile}), 这样编译时会编译所有./path下的模块,但运行时确定myFile的值才会加载,从而实现懒加载。

在这里插入图片描述

解决方案二:

function lazyLoadView(AsyncView) {
  const AsyncHandler = () => ({
    component: AsyncView,
      // A component to use while the component is loading.
    loading: require('@/view/system/Loading.vue').default,
      // A fallback component in case the timeout is exceeded
      // when loading the component.
    error: require('@/view/system/Timeout.vue').default,
      // Delay before showing the loading component.
      // Default: 200 (milliseconds).
    delay: 200,
      // Time before giving up trying to load the component.
      // Default: Infinity (milliseconds).
    timeout: 10000
  });
  return Promise.resolve({
    functional: true,
    render(h, { data, children }) {
        // Transparently pass any props or children
        // to the view component.
      return h(AsyncHandler, data, children);
    }
  });
}
const My = () => lazyLoadView(import('@/view/My.vue'));
const router = new VueRouter({
  routes: [
    {
      path: '/my',
      component: My
    }
  ]
})

通过上述两种方法都能够解决 动态组件的懒加载效果

感谢
https://blog.youkuaiyun.com/zjcjava/article/details/82179975
https://blog.youkuaiyun.com/weixin_37221852/article/details/81297430

Vue 中动态加载组件是一种常见的需求,尤其是在实现懒加载、按需加载或根据用户权限/状态动态渲染组件时。Vue 提供了多种方式来实现**动态加载组件**,主要包括: - `<component :is="...">` 动态切换组件 - 异步组件(结合 `import()` 实现懒加载) - 路由中懒加载组件(适用于 Vue Router) 下面我将详细说明并给出代码示例。 --- ### ✅ 1. 使用 `<component :is>` 动态切换组件 这是最基本的动态组件用法,使用内置的 `<component>` 标签配合 `:is` 属性来动态切换组件。 ```vue <template> <div> <button @click="currentComponent = 'ComponentA'">显示 A</button> <button @click="currentComponent = 'ComponentB'">显示 B</button> <!-- 动态组件 --> <component :is="currentComponent" /> </div> </template> <script> import ComponentA from './components/ComponentA.vue' import ComponentB from './components/ComponentB.vue' export default { components: { ComponentA, ComponentB }, data() { return { currentComponent: 'ComponentA' } } } </script> ``` > 上述代码中,`:is` 绑定的是注册过的组件名,点击按钮会动态切换显示的组件。 --- ### ✅ 2. 异步组件懒加载)—— 使用 `defineAsyncComponent` (Vue 3) Vue 3 提供了 `defineAsyncComponent` 来定义异步加载的组件,可以配合 `import()` 实现代码分割和懒加载。 ```vue <template> <div> <button @click="showAsync = !showAsync">切换异步组件</button> <component v-if="showAsync" :is="AsyncComponent" /> </div> </template> <script setup> import { ref, defineAsyncComponent } from 'vue' // 定义异步组件 const AsyncComponent = defineAsyncComponent(() => import('./components/HeavyComponent.vue') // 懒加载组件 ) const showAsync = ref(false) </script> ``` > 这种方式会在首次渲染时才加载 `HeavyComponent.vue`,适合用于体积大、不常使用组件(如模态框、图表等)。 --- ### ✅ 3. 带 loading 和 error 处理的异步组件 你还可以为异步组件添加加载中和错误状态: ```js const AsyncComponent = defineAsyncComponent({ loader: () => import('./components/HeavyComponent.vue'), loadingComponent: LoadingSpinner, errorComponent: ErrorComponent, delay: 200, // 延迟显示 loading(避免闪烁) timeout: 5000 // 超时时间 }) ``` --- ### ✅ 4. 在路由中动态加载组件Vue Router) 如果你使用 Vue Router,也可以在路由配置中实现组件懒加载: ```js const routes = [ { path: '/dashboard', component: () => import('./views/Dashboard.vue') // webpack 代码分割 }, { path: '/profile', component: () => import('./views/Profile.vue') } ] ``` > 注意:这种写法依赖打包工具(如 Vite 或 Webpack)支持动态 `import()`,会自动做 code-splitting。 --- ### ✅ 5. 动态导入组件并注册(运行时动态路径) 有时候你需要根据字符串动态加载组件(比如从后端返回组件名): ```js const loadComponent = async (componentName) => { try { const module = await import(`./components/${componentName}.vue`) return module.default } catch (err) { console.error(`无法加载组件 ${componentName}`, err) return { template: '<div>组件加载失败</div>' } } } // 使用示例 const comp = await loadComponent('SidebarMenu') this.currentComponent = comp ``` > ⚠️ 注意:这种方式在 Vite 中有局限性,因为 `import()` 不支持完全动态路径(如变量拼接),需要使用明确路径或构建时能分析到的路径。推荐使用映射表: ```js const componentMap = { 'sidebar': () => import('./components/Sidebar.vue'), 'header': () => import('./components/Header.vue') } const loadComponent = async (key) => { if (componentMap[key]) { const module = await componentMap[key]() return module.default } } ``` --- ### 总结 | 方式 | 用途 | 是否懒加载 | |------|------|-----------| | `<component :is>` | 动态切换已注册组件 | 否 | | `defineAsyncComponent` | 异步懒加载组件 | 是 | | 路由 `component: () => import(...)` | 页面级懒加载 | 是 | | 动态 `import()` + 映射表 | 运行时按需加载组件 | 是 | ---
评论 11
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值