Vue3 + Vue Router4下如何获取懒加载路由组件并实现同目录组件预加载
Vue3 + Vue Router4下如何获取懒加载路由组件并实现同目录组件预加载
嘿,这个需求挺实用的!我来一步步帮你实现同目录懒加载组件的预加载,完美契合你现在用的Vue3.4.27和Vue Router4.3.2环境。
首先得给你的路由配置加个小标记,不然没法从当前路由关联到对应的组件目录——毕竟懒加载的组件路径是写在路由里的,但我们需要统一标识哪些路由属于同一个组件组。
第一步:给同组路由添加元信息
修改你的路由配置,给每个属于/path/to/下的路由加上meta.componentDir,把组件所在的目录路径存进去,这样后续就能通过当前路由快速拿到目录地址:
const routes = [ { path: '/path/to/pageone', component: () => import('../components/MyStuff/PageOne.vue'), meta: { componentDir: '../components/MyStuff/' } }, { path: '/path/to/pagetwo', component: () => import('../components/MyStuff/PageTwo.vue'), meta: { componentDir: '../components/MyStuff/' } }, // 其他同组的PageThree、PageFour等路由都照这个格式加meta ]
第二步:完善你的Composable,实现预加载逻辑
接下来我们把你已经开始写的composable补全,核心就是通过当前路由的元信息拿到目录,再获取该目录下所有Vue组件,最后触发预加载。这里要注意你用的构建工具是Webpack还是Vite,两者的静态文件扫描方式不一样:
情况1:项目用Webpack构建
import { watch, onMounted } from 'vue' import { useRoute } from 'vue-router' export function usePreloadSiblingComponents() { const route = useRoute() // 核心预加载函数 const preloadComponents = () => { // 从当前路由元信息拿组件目录,没有的话直接返回 const componentDir = route.meta.componentDir if (!componentDir) return // 用Webpack的require.context扫描目录下所有.vue文件 const componentsContext = require.context( componentDir, false, // 设为true可以扫描子目录,这里你不需要就设false /\.vue$/ // 只匹配.vue后缀的文件 ) // 拿到所有组件的相对路径,再拼接成完整的导入路径 const fullComponentPaths = componentsContext.keys().map(relativePath => { // require.context返回的key是./PageOne.vue这种,所以要去掉开头的./ return `${componentDir}${relativePath.slice(2)}` }) // 循环触发预加载,Webpack/Vite会自动缓存已加载的组件,重复调用也不会重复下载 fullComponentPaths.forEach(path => { import(path).catch(err => console.error('预加载组件失败:', err)) }) } // 页面挂载时触发一次预加载 onMounted(() => { preloadComponents() }) // 监听路由变化,切换到同组其他页面时也触发预加载(可选,防止新增组件没被加载) watch( () => route.fullPath, () => preloadComponents() ) }
情况2:项目用Vite构建
Vite不支持require.context,要用它自带的import.meta.glob来扫描文件,调整一下composable:
import { watch, onMounted } from 'vue' import { useRoute } from 'vue-router' export function usePreloadSiblingComponents() { const route = useRoute() // Vite环境下用异步函数,因为import.meta.glob返回的是异步导入函数 const preloadComponents = async () => { const componentDir = route.meta.componentDir if (!componentDir) return // 用import.meta.glob匹配目录下所有.vue文件 const componentImports = import.meta.glob(`${componentDir}*.vue`) // 遍历所有组件导入函数,触发预加载 for (const [_, importFn] of Object.entries(componentImports)) { try { await importFn() } catch (err) { console.error('预加载组件失败:', err) } } } onMounted(() => { preloadComponents() }) watch( () => route.fullPath, () => preloadComponents() ) }
第三步:在页面组件中使用这个Composable
最后,只要在属于/path/to/组的任意页面组件里调用这个composable就行,比如在PageFour.vue里:
<script setup> import { usePreloadSiblingComponents } from '@/composables/usePreloadSiblingComponents' // 页面挂载后就会自动预加载MyStuff目录下的所有组件 usePreloadSiblingComponents() </script>
一些小提醒
- 如果你需要扫描子目录,记得把Webpack的
require.context第二个参数改成true,Vite的glob改成${componentDir}**/*.vue - 可以在预加载时过滤掉当前组件,比如通过对比当前路由的组件路径,但其实重复调用
import也没关系,构建工具会自动缓存,不会重复下载 - 一定要保证
meta.componentDir的路径和你路由里组件导入的路径完全一致,不然会找不到文件
备注:内容来源于stack exchange,提问作者Bob Ramsey
相关产品推荐
相关产品推荐

