0

所以我的vue3项目有问题。要点:我需要为某些用例支持不同的布局:授权、用户配置文件的布局、组的布局等。我通过这种方式得到了机会:

  1. 创建AppLayout.vue用于管理布局的组件
<template>
    <component :is="layout">
        <slot />
    </component>
</template>

<script>
import AppLayoutDefault from "@/layouts/EmptyLayout";

import { shallowRef, watch } from "vue";
import { useRoute } from "vue-router";
export default {
    name: "AppLayout",
    setup() {
        const layout = shallowRef(AppLayoutDefault);
        const route = useRoute();
        watch(
            () => route.meta,
            async (meta) => {
                try {
                    const component =
                        await require(`@/layouts/${meta.layout}.vue`);
                    layout.value = component?.default || AppLayoutDefault;
                } catch (e) {
                    layout.value = AppLayoutDefault;
                }
            }
        );
        return { layout };
    },
};
</script>
  1. 所以我App.vue开始看起来如此
<template>
    <AppLayout>
        <router-view />
    </AppLayout>
</template>
  1. 为了呈现特定的布局,我添加了路由器的index.js特殊标签meta
 {
    path: '/login',
    name: 'LoginPage',
    component: () => import('../views/auth/LoginPage.vue')
 },
 {
    path: '/me',
    name: 'MePage',
    component: () => import('../views/user/MePage.vue'),
    meta: {
      layout: 'ProfileLayout'
    },
  },
  1. 现在我可以创建一些布局。例如,我制作ProfileLayout.vue了一些嵌套组件:页眉和页脚。我使用插槽来呈现动态页面内容。
<template>
<div>
    <div class="container">
        <Header />
        <slot />
        <Footer />
    </div>
</div>
</template>

因此,当我键入 URL http://example.com/profile时,我会看到基于 ProfileLayout 的 Profile 页面的内容。这里的问题是:Profile page 调用 hooks 两次

我放入console.log()created() 钩子,我看到以下内容 创建组件的日志

这是问题,因为我在钩子中有一些请求,它们也执行了两次。我是vuejs的新手,对vue如何渲染组件不是很了解。我建议在代码内部调用重新渲染并再次创建配置文件页面。如何预防?

4

1 回答 1

1

您的个人资料页面加载了两次,因为它实际上......必须加载两次。这是渲染流程,不准确,但您可以理解:

  1. 你的 layout.value=AppDefaultLayout。动态组件<component :is="layout">将首先呈现它,因为 meta.layout 在初始时未定义。ProfilePage 在这一点上也被渲染了。
  2. meta.layout 现在有值 & 观察者对 layout.value =><component :is="layout">重新渲染第二次进行了更改,同样适用于 ProfilePage

所以解决这个问题我干脆去掉默认值,动态组件不再需要渲染默认布局。如果它没有价值,那么它不应该渲染任何东西。

  <keep-alive>
    <component :is="layout">
      <slot />
    </component>
  </keep-alive>
import { markRaw, shallowRef, watch } from "vue";
import { useRoute } from "vue-router";


export default {
  name: "AppLayout",
  setup() {
    console.debug("Loaded DynamicLayout");
    const layout = shallowRef()
    const route = useRoute()

    const getLayout = async (lyt) => {
      const c = await import(`@/components/${lyt}.vue`);
      return c.default;
    };

    watch(
      () => route.meta,
      async (meta) => {
        console.log('...', meta.layout);
        try {
          layout.value = markRaw(await getLayout(meta.layout));
        } catch (e) {
          console.warn('%c Use AppLayoutDefault instead.\n', 'color: darkturquoise', e);
          layout.value = markRaw(await getLayout('EmptyLayout'));
        }
      }
    );
    return { layout }
  },
};
于 2022-01-04T06:05:07.897 回答