79134548

Date: 2024-10-28 17:52:41
Score: 0.5
Natty:
Report link

I had what I think is a similar issue to what you are describing, and I found this article very useful.

You do not need to insert the layouts directly on each page or view. Instead, create a Container layout:

// src/layouts/AppContainerLayout.vue

<template>
    <component :is="this.$route.meta.layoutComponent">
        <slot />
    </component>
</template>

<script>
export default {
    name: "AppContainerLayout"
}
</script>

Then, update your App.vue file to include the Container layout:

// src/App.vue

<script setup>
import AppContainerLayout from './layouts/AppContainerLayout.vue';
</script>

<template>
  <AppContainerLayout>
    <RouterView />
  </AppContainerLayout>
</template>

Next, you can set up your router the same way you described but now you can add a call to a middleware to load the layout previously associated with the selected route:

// src/router/router.js

import { createRouter, createWebHistory } from "vue-router";
import { loadLayoutMiddleware } from "./middleware/loadLayoutMiddleware";
import HomeView from "../views/HomeView.vue";
import AnotherView from "../views/AnotherView.vue";
import NotFoundView from "../views/NotFoundView.vue";

const routes = [
  {
    path: "/",
    name: "Home",
    component: HomeView,
    meta: {
      layout: "AppLayoutDashboard",
    },
  },
  {
    path: "/another_view",
    name: "Another",
    component: AnotherView,
  },
  {
    path: "/:pathMatch(.*)*",
    name: "NotFound",
    component: NotFoundView,
    meta: {
      layout: "AppLayoutError",
    },
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

router.beforeEach(loadLayoutMiddleware);

export default router;

This is the layout middleware associated with the router that I found in the repository from the same article with a minor update to load the default layout when no layout is declared within the route:

// src/router/middleware/loadLayoutMiddleware.js

export async function loadLayoutMiddleware(route) {
  try {
    let layout = route.meta.layout || "DefaultLayout";

    let layoutComponent = await import(`@/layouts/${layout}.vue`);
    route.meta.layoutComponent = layoutComponent.default;
  } catch (e) {
    console.error("Error occurred in processing of layouts: ", e);
    console.log("Mounted DefaultLayout");
    let layout = "DefaultLayout";
    let layoutComponent = await import(`@/layouts/${layout}.vue`);
    route.meta.layoutComponent = layoutComponent.default;
  }
}

You can take out the logs once you check that it works properly. Remember to clean your views from any references to layouts

// src/views/HomeView.vue:

<template>
    <!-- VIEW CODE HERE -->
</template>

Finally, the only thing missing at this point is to create the custom layouts but you have that covered:

// src/layouts/AppLayoutDashboard.vue

<template>
  <div style="border: 2px solid red">
    <h1>AppLayoutDashboard.vue</h1>

    <slot/>
  </div>
</template>

// src/layouts/DefaultLayout.vue

<template>
  <div style="border: 2px solid red">
    <h1>DefaultLayout.vue</h1>

    <slot/>
  </div>
</template>

// src/layouts/AppLayoutError.vue

<template>
  <div style="border: 2px solid red">
    <h1>AppLayoutError.vue</h1>

    <slot/>
  </div>
</template>
Reasons:
  • Blacklisted phrase (1): this article
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (1):
Posted by: jpotterh