Vue router layouts

c8e8b15f6b2ac9525d94b6ee239a851d

Добавление 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

Создаем дополнительно ещё один произвольный шаблон tabs, который будет реализовывать страницу в виде табов, где табы — ссылка на страницу:

// @/layouts/components/tabs


Создаем еще один дополнительный шаблон extra для демонстрации:

// @/layouts/components/extra

В корне проекта, в моем случае это 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.

© Habrahabr.ru