Использование навигационных цепочек может быть полезным для сложных сайтов, поскольку они дают пользователям четкое визуальное представление об иерархии сайта и более простой подход для пользователя, чтобы отслеживать свои шаги, улучшая их опыт и вовлеченность, а также снижая показатели отказов для наших сайтов. .

В этом посте мы рассмотрим пошаговый процесс создания интуитивно понятного компонента Breadcrumbs с помощью Nuxt и пользовательского интерфейса Storefront в нашем подробном руководстве.

Важность хлебных крошек в веб-навигации

Тропа хлебных крошек отображает текущее местоположение в веб-приложении в контексте иерархии приложения и позволяет пользователям легко возвращаться к предыдущим страницам или уровням. Он предлагает альтернативное визуальное представление для облегчения навигации, часто горизонтальную последовательность текстовых ссылок, разделенных символом >, чтобы указать уровень вложенности текста, следующего за ним.

Вы можете просматривать хлебные крошки как иерархию каталогов файлов, где корень отображается первым, а ссылка на текущую страницу отображается последней.

Существует три типа хлебных крошек: на основе местоположения, атрибута и пути. В этом посте будет обсуждаться реализация компонента Breadcrumbs на основе пути для нашего приложения Nuxt с использованием его механизма маршрутизации и пользовательского интерфейса Storefront для визуального отображения.

Примечание. Для приложения Vue с установленным Vue Router вы можете легко повторно использовать обсуждаемый в этом посте код с небольшими изменениями.

Предпосылки

Было бы полезно, если бы у вас было настроено и готово к работе приложение Nuxt с помощью следующей команды:

npx nuxi init breadcrumbs-demo

Какой breadcrumbs-demo является названием нашего демо-приложения кода. Вы можете изменить имя на любое по своему усмотрению.

Далее давайте добавим в наш проект пользовательский интерфейс Storefront, установив его пакет и модуль TailwindCSS для Nuxt с помощью следующей команды:

yarn add -D @nuxtjs/tailwindcss @storefront-ui/vue

Вы должны следовать Инструкциям по пользовательскому интерфейсу Storefront, чтобы настроить TailwindCSS и пользовательский интерфейс Storefront вместе в продукте Nuxt. После этого мы готовы к нашему уроку!

Понимание файловой системы маршрутизации

Nuxt использует Vue Router и файловую систему для создания маршрутов приложения из файлов в каталоге /pages. Например, если у вас есть следующая файловая структура:

\page 
|--index.vue 
|--\products 
|-----index.vue 
|-----details.vue

За кулисами движок Nuxt автоматически построит следующие маршруты:

  • \ в качестве домашней страницы с pages\index.vue в качестве компонента представления. Его имя будет index, такое же, как имя файла.
  • \products с pages\products\index.vue и имеет products в качестве имени.
  • \products\details для представления pages\products\details с именем products-details, поскольку details вложено в products.

Вы можете просмотреть маршруты, используя метод getRoutes() экземпляра маршрутизатора. Вы также можете назвать маршрут динамическим, используя синтаксис [], например [sku].vue. В этом случае Nuxt сгенерирует динамический путь как /:sku(), где :sku() является шаблоном Regex, который Vue Router будет использовать для сопоставления и извлечения целевых параметров в поле sku, когда это уместно.

Большой. Теперь мы понимаем, как работает система маршрутизации в Nuxt. Мы можем построить наш механизм хлебных крошек, разбивая URL на крошки.

Создание компонуемого файла useBreadcrumbs

Чтобы построить наши хлебные крошки, мы создаем компонуемый объект useBreadcrumbs(), в котором выполняем следующие действия:

  1. Следите за изменениями маршрута, особенно в свойствах name, path и meta, а не всего объекта route.
  2. Инициализируйте значение по умолчанию для нашего массива breadcrumbs в качестве маршрута Home.
  3. Немедленно активируйте наблюдатель, чтобы у нас также были подсчитаны хлебные крошки при начальной загрузке или обновлении страницы.
  4. Передайте breadcrumbs в качестве возвращаемого значения для компонуемого.
  5. Мы запускаем наблюдателей только тогда, когда текущий маршрут не находится на главной странице.

Основной код для useBreadcrumbs() выглядит следующим образом:

export const useBreadcrumbs = () => {
    const route = useRoute()

    const HOMEPAGE = { name: 'Home', path: '/' };
    const breadcrumbs:Ref<Array<{ name: string; path: string; }>> = ref([ HOMEPAGE ])

    watch(() => ({
        path: route.path,
        name: route.name,
        meta: route.meta,
        matched: route.matched,
    }), (route) => {
        if (route.path === '/') return;
    
        //TODO - generate the breadcrumbs
    }, {
        immediate: true,
    })

    return {
        breadcrumbs
    }
}

Далее мы реализуем, как вычислять хлебные крошки из текущего маршрута, включая динамические и вложенные способы.

Обработка динамических и вложенных маршрутов

Для создания хлебных крошек страницы всегда лучше, чтобы текущий маршрут знал, кто его родитель. Однако в Vue Router и Nuxt, к сожалению, такой возможности нет. Вместо этого мы можем построить пути хлебных крошек, рекурсивно разрезая текущий путь хлебных крошек по последнему индексу символа /.

Возьмем, к примеру, наш путь /products/about/keychain. Мы разобьем его на следующие пути: "/products/about/keychain", "/products/about", "/products" и "". Каждый путь — это хлебная крошка, которую нам нужно отобразить. И чтобы получить отображаемое имя для этих хлебных крошек, нам нужно сделать следующее:

  1. Получите список доступных маршрутов из router экземпляра useRouter().
  2. Мы найдем соответствующий маршрут для каждого пути хлебных крошек.
  3. Наше условие остановки — это когда сокращенный путь — Домашняя страница.

Наш код для getBreadcrumbs() выглядит следующим образом:

function getBreadcrumbs(currPath: string): any[] {
    //1. When we reach the root, return the array with the Home route
    if (currPath === '') return [ HOMEPAGE ];

    //2. Continue building the breadcrumb for the parent's path
    const parentRoutes = getBreadcrumbs(currPath.slice(0, currPath.lastIndexOf('/')));

    //3. Get the matching route object
    //TODO
    //4. Return the merged array with the new matching route
    return [
        ...parentRoutes,
        {
            path: currPath,
            //TODO
            name: currPath,
        }
    ]
}

В настоящее время мы возвращаем currPath как path и name для хлебных крошек. Тем не менее, мы должны реализовать способ обнаружения соответствующего маршрута на основе сгенерированных конфигураций маршрутов из Nuxt, включая динамические маршруты и динамические вложенные маршруты. Давайте сделаем это дальше.

Соответствие шаблону маршрута

При работе с соответствующими путями маршрутов возникает множество сценариев, связанных с динамическими маршрутами, которые нам необходимо обработать, в том числе:

  • Динамические маршруты, такие как /products/:id()
  • Динамический маршрут и статический маршрут для одного родителя, например /products/:id() (pages/produts/[id].vue) и /products/about (pages/products/about.vue)
  • Динамический маршрут, вложенный в другой динамический маршрут, например /products/:id()/:field()

Самый простой подход — разбить маршрут и текущий путь на части с помощью разделителя /. Затем мы повторяем элементы и сравниваем один к одному, чтобы увидеть, является ли это одним и тем же значением или начинается ли подпуть с :, как показано в следующем коде для isMathPatternPath:

const isMathPatternPath = (pathA: string, pathB: string) => {
    const partsA = pathA.split('/');
    const partsB = pathB.split('/');

    if (partsA.length !== partsB.length) return false;

    const isMatch = partsA.every((part: string, i: number) => {
        return part === partsB[i] || part.startsWith(':');
    })
    
    return isMatch;
}

Затем мы используем isMathPatternPath в нашей функции getBreadcrumbs() на currPath и в результате получаем массив совпадающих маршрутов со следующими предположениями:

  • Если есть статический маршрут, а динамический маршрут находится на одном родительском объекте, они будут совпадать для обоих.
  • Статические маршруты всегда будут отображаться перед динамическими маршрутами в таком массиве сопоставленных маршрутов (буквы появляются перед такими символами, как «:»).
  • Совпадающий массив содержит более одного результата для статического маршрута с динамическим одноуровневым маршрутом. В этом случае мы возьмем точное совпадение, используя сравнение ===. В противном случае массив должен содержать один результат.

И таким образом, наша реализация для getBreadcrumbs() будет такой:

function getBreadcrumbs(currPath: string): any[] {
    //1. When we reach the root, return the array with Home route
    if (currPath === '') return [ HOMEPAGE ];

    //2. Continue building the breadcrumb for the parent's path
    const parentRoutes = getBreadcrumbs(currPath.slice(0, currPath.lastIndexOf('/')));

    //3. Get the matching route object
    const founds = routes.filter(r => isMathPatternPath(r.path, currPath));
    const matchRoute = founds.length > 1 ? founds.find(r => r.path === currPath) : founds[0];

    //4. Return the merged array with the new matching route
    return [
        ...parentRoutes,
        {
            path: currPath,
            name: matchRoute?.meta?.breadcrumb || matchRoute?.name || matchRoute?.path || currPath,
        }
    ]
}

На основе matchRoute мы будем использовать поле meta.breadcrumb, чтобы получить желаемое имя для отображения, или его имя, путь или currPath в качестве резервного значения.

И мы можем обновить наш компонуемый useBreadcrumbs() следующим кодом:

export const useBreadcrumbs = () => {
    //...

    watch(() => ({
        path: route.path,
        name: route.name,
        meta: route.meta,
        matched: route.matched,
    }), (route) => {
        if (route.path === '/') return;

        breadcrumbs.value = getBreadcrumbs(route.path);
    }, {
        immediate: true,
    })

    //...
}

После этого наш useBreadcrumbs() готов к использованию. Давайте покажем это!

Интеграция с компонентом пользовательского интерфейса

Мы скопируем код Хлебных крошек Storefront UI со значком «Домой» и вставим в наш components/Breadcrumbs.vue.

В разделе script setup мы изменим breadcrumbs на props следующим образом:

const props = defineProps({
  breadcrumbs: {
    type: Array,
    required: true,
  },
});

В примере кода каждая навигационная цепочка имеет name и link. Следовательно, нам нужно найти item.link и заменить их на item.path в разделе template. Кроме того, мы хотим отображать SfLink как NuxtLink, чтобы избежать полной перезагрузки страницы, добавляя :tag="NuxtLink" к каждому SfLink, появляющемуся в template, и следующее к разделу script:

import { resolveComponent } from 'vue';

const NuxtLink = resolveComponent('NuxtLink');

Большой. Наш компонент Breadcrumbs готов.

Теперь в /layouts/default.vue мы получим breadcrumbs из компонуемого useBreadcrumbs() и передадим его компоненту Breadcrumbs для рендеринга, как показано ниже:

<template>
    <Breadcrumbs class="mt-4 ml-4" :breadcrumbs="breadcrumbs"/>
    <div class="h-px m-4 bg-neutral-200 divider"></div>
    <slot />
</template>
<script setup>
import { useBreadcrumbs } from '../composables/useBreadcrumbs';

const { breadcrumbs } = useBreadcrumbs();
</script>

Наконец, убедитесь, что в вашем app.vue есть следующий код:

<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

И это все, что нужно. Когда мы переходим на страницу, приложение отображает соответствующие хлебные крошки:

Как вы заметили, текущие хлебные крошки используют имя по умолчанию, определенное в сопоставленном маршруте, которое только иногда можно прочитать. В нашей реализации мы использовали route.meta?.breadcrumb в качестве имени хлебной крошки. Чтобы определить meta.breadcrumb, мы будем использовать встроенный метод Nuxt definePageMeta, как в следующем примере:

<script setup>
/**pages/products/index.vue */
definePageMeta({
    breadcrumb: 'Products Gallery',
})
</script>

Во время сборки Nuxt объединит метаданные нужной страницы с meta маршрута, и у нас будут соответствующие хлебные крошки:

Обратите внимание, что вы не можете определить мета, следуя описанному выше подходу для динамического маршрута. Вместо этого в useBreadcrumbs вы можете просмотреть route.params и получить соответствующее имя из параметров и соответствующих данных, таких как название продукта.

Краткое содержание

Рабочий код вы можете найти здесь.

В этом посте мы рассмотрели, как создать механизм хлебных крошек для нашего приложения Nuxt, используя его встроенный маршрутизатор, и визуализировать их с помощью компонента хлебных крошек с помощью пользовательского интерфейса Storefront. Реализация проста и может быть не оптимальной по сравнению с такими подходами, как Regex, в более сложной системе маршрутизации с несколькими уровнями вложенных динамических и статических маршрутов. Тем не менее, это хорошая отправная точка для создания собственной системы хлебных крошек, и помните о правилах KISS!

Я надеюсь, что вы найдете этот пост полезным. Если у вас есть какие-либо вопросы или предложения, пожалуйста, оставьте комментарий ниже. Я хотел бы услышать от вас.

👉 Если хотите иногда быть со мной в курсе, подпишитесь на меня в Твиттере | Фейсбук.

👉 Узнайте больше о Vue из моей новой книги Learning Vue. Ранний выпуск уже доступен для чтения!

Понравился этот пост или нашел его полезным? Поделись 👇🏼 😉

Первоначально опубликовано на https://mayashavin.com.