路由器级别的 Vue 3 动态组件
Vue 3 dynamic components at router level
我需要动态导入,例如。我有10个布局,但用户只访问了3个布局,我不应该导入所有布局,因为它消耗了不必要的资源。
自动态导入以来,每次我在登录和注册路径 <RouterLink :to"{name: 'Login'}" />
和 <RouterLink :to"{name: 'Register'}" />
之间切换时,我都会重新渲染或再次动态导入布局。
我的问题是什么是更好的处理方式,无需重新渲染或再次动态导入布局?或者我可以将动态导入组件保存到当前的 vue 3 上下文中吗?
App.vue 这是我的应用,根据route.meta.layout
看路由器和切换布局
<template>
<component :is="layout.component" />
</template>
<script>
import DefaultLayout from "./layout/default.vue";
import {
ref,
shallowRef,
reactive,
shallowReactive,
watch,
defineAsyncComponent,
} from "vue";
import { useRoute } from "vue-router";
export default {
name: "App",
setup(props, context) {
const layout = shallowRef(DefaultLayout);
const route = useRoute();
watch(
() => route.meta,
async (meta) => {
if (meta.layout) {
layout = defineAsyncComponent(() =>
import(`./layout/${meta.layout}.vue`)
);
} else {
layout = DefaultLayout;
}
},
{ immediate: true }
);
return { layout };
},
};
</script>
router/index.js 这是我的布局元路由器
import { createRouter, createWebHistory } from "vue-router";
import Home from "@/views/Home.vue";
import NotFound from "@/views/NotFound.vue";
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/login",
name: "Login",
meta: {
layout: "empty",
},
component: function () {
return import(/* webpackChunkName: "login" */ "../views/Login.vue");
},
},
{
path: "/register",
name: "Register",
meta: {
layout: "empty",
},
component: function () {
return import(/* webpackChunkName: "register" */ "../views/Register.vue");
},
},
{ path: "/:pathMatch(.*)", component: NotFound },
];
const router = createRouter({
history: createWebHistory(import.meta.env.VITE_GITLAB_BASE_PATH),
routes,
scrollBehavior(to, from, savedPosition) {
// always scroll to top
return { top: 0 };
},
});
export default router;
您可以在 components 选项中使用 AsyncComponent
并只使用 returns 当前布局的计算 属性 ,这将仅加载当前布局而不加载其他布局 :
components: {
layout1: defineAsyncComponent(() => import('./components/Layout1.vue')),
layout2: defineAsyncComponent(() => import('./components/Layout2.vue')),
},
遇到这个问题,Vue 核心团队的 Thorsten Lünborg 帮助了我。
添加 v-if 条件,应该可以解决它。
<component v-if="layout.name === $route.meta.layout" :is="layout">
我需要动态导入,例如。我有10个布局,但用户只访问了3个布局,我不应该导入所有布局,因为它消耗了不必要的资源。
自动态导入以来,每次我在登录和注册路径 <RouterLink :to"{name: 'Login'}" />
和 <RouterLink :to"{name: 'Register'}" />
之间切换时,我都会重新渲染或再次动态导入布局。
我的问题是什么是更好的处理方式,无需重新渲染或再次动态导入布局?或者我可以将动态导入组件保存到当前的 vue 3 上下文中吗?
App.vue 这是我的应用,根据route.meta.layout
看路由器和切换布局<template>
<component :is="layout.component" />
</template>
<script>
import DefaultLayout from "./layout/default.vue";
import {
ref,
shallowRef,
reactive,
shallowReactive,
watch,
defineAsyncComponent,
} from "vue";
import { useRoute } from "vue-router";
export default {
name: "App",
setup(props, context) {
const layout = shallowRef(DefaultLayout);
const route = useRoute();
watch(
() => route.meta,
async (meta) => {
if (meta.layout) {
layout = defineAsyncComponent(() =>
import(`./layout/${meta.layout}.vue`)
);
} else {
layout = DefaultLayout;
}
},
{ immediate: true }
);
return { layout };
},
};
</script>
router/index.js 这是我的布局元路由器
import { createRouter, createWebHistory } from "vue-router";
import Home from "@/views/Home.vue";
import NotFound from "@/views/NotFound.vue";
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/login",
name: "Login",
meta: {
layout: "empty",
},
component: function () {
return import(/* webpackChunkName: "login" */ "../views/Login.vue");
},
},
{
path: "/register",
name: "Register",
meta: {
layout: "empty",
},
component: function () {
return import(/* webpackChunkName: "register" */ "../views/Register.vue");
},
},
{ path: "/:pathMatch(.*)", component: NotFound },
];
const router = createRouter({
history: createWebHistory(import.meta.env.VITE_GITLAB_BASE_PATH),
routes,
scrollBehavior(to, from, savedPosition) {
// always scroll to top
return { top: 0 };
},
});
export default router;
您可以在 components 选项中使用 AsyncComponent
并只使用 returns 当前布局的计算 属性 ,这将仅加载当前布局而不加载其他布局 :
components: {
layout1: defineAsyncComponent(() => import('./components/Layout1.vue')),
layout2: defineAsyncComponent(() => import('./components/Layout2.vue')),
},
遇到这个问题,Vue 核心团队的 Thorsten Lünborg 帮助了我。 添加 v-if 条件,应该可以解决它。
<component v-if="layout.name === $route.meta.layout" :is="layout">