Vue router layouts
Добавление layout системы в существующий проект на Vue с использованием Vue router.
В данном примере будем рассматривать проект на Vue2 options api с использование Vue Router v3. В теории не вижу особых проблем в применении для Vue3 с composition api.
Репозиторий с реализацией
Задача: ускорить создание типовых страниц по средствам layout системы с возможностью передачи названия необходимого шаблона для страницы примерно похожей на реализацию в nuxt3.
Создаем директорию для наших шаблонов в корне проекта @/layouts
Оформляем основной компонент в котором будем определять нужный шаблон:
// @/layouts/index.vue
Создаем рядом директорию для будущих шаблонов @/layouts/components
Создаем default шаблон для компонентов:
// @/layouts/components/default.vue
// Ваша логика для default layout
// ключающая в себя router-view
// Например
My header
Создаем дополнительно ещё один произвольный шаблон tabs, который будет реализовывать страницу в виде табов, где табы — ссылка на страницу:
// @/layouts/components/tabs
{{ tab.title }}
Создаем еще один дополнительный шаблон extra для демонстрации:
// @/layouts/components/extra
Extra layout
В корне проекта, в моем случае это App.vue в корне проекта, используем ранее созданный компонент
// Было
//
// Стало
Создаем базовую структуру router, согласно документации vue-router, в приложении либо используем существующую:
const routes = [
{
path: "/",
component: () => import(Ваш компонент страницы),
...
}
...
]
Для определения нужного layout используем router.meta:
{
path: "/",
components: () => import(Ваш компонент),
meta: {
layout: "extra",
},
}
Для определения табов так же можно используем router.meta в родительском route, для этого нужно будет немного обновить код в нашем @/layouts/index:
Если проект полностью на Vue и Vue-router, можно привязаться к children и из них формировать структуру дочерних табов, для этого обновим computed в компоненте
{
computed: {
...
layoutTabs() {
// при использовании parentRoute.children как табы
if (this.parentChildren) {
return this.parentChildren.map((i, k) => {
return {
path: i.path,
title: 'tabTitle' in i.meta && i.meta.tabTitle || `tab${k}`,
}
});
}
// при передачи табов как meta.layoutTabs
if (this.layoutType === 'tabs') {
if (this.routeHaveLayoutTabs) {
return this.$route.meta.layoutTabs;
}
if (this.parentRouteHaveLayoutTabs) {
return this.parentRoute.meta.layoutTabs;
}
return [];
}
return [];
},
// находим children текущего route
parentChildren() {
if (!this.parentRoute) return [];
const parentRoute = this.$router.options.routes.find(i => this.parentRoute.regex.test(i.path) );
return parentRoute && parentRoute.children;
},
}
}
При использовании в дочерних route своего собственного layout и наличии его собственных дочерних route оформляем код в формате:
[
{
path: "default",
component: () => import("компонент страницы"),
},
{
path: "tabs",
redirect: "/tabs/red",
meta: {
layout: "tabs",
layoutTabs: массив табов // если берем табы из meta
},
children: [
{
path: "red",
component: () => import("компонент заглушка который состоит из одного "),
// кейс с еще более глубокой вложенностью и самостоятельным компонентом для родительского route "red"
children: [
{
// для корневого роута "red"
path: "",
component: () => import("ваш компонент red страницы"),
},
{
path: "orange",
component: () => import("ваш компонент oragne страницы"),
meta: {
layout: "extra",
},
},
{
path: "tomato",
component: () => import("ваш компонент tomato страницы"),
meta: {
layout: "extra",
},
}
],
},
{
path: "green"
component: () => import("ваш компонент green страницы"),
},
{
path: "blue",
component: () => import("ваш компонент blue страницы"),
}
]
}
]
Полную реализацию примера можно посмотреть на Github.