Руководство по Vue Router для новичков

Vue 3 Изучение

В этом руководстве мы рассмотрим, как реализовать маршрутизацию в приложении Vue с помощью Vue Router. Чтобы у нас была практическая практика, мы создадим простое приложение Pokedex, используя Vue и Vue Router.

В частности, мы рассмотрим следующее:

  • настройка роутера
  • параметры маршрута
  • декларативная и программная навигация
  • вложенные маршруты
  • 404 страницы

Каждой платформе пользовательского интерфейса JavaScript, которая позволяет создавать одностраничные приложения, необходим способ перехода пользователей с одной страницы на другую. Всем этим нужно управлять на стороне клиента, синхронизируя представление, которое в настоящее время отображается на странице, с URL-адресом в адресной строке. В мире Vue [официальной библиотекой] для управления этим типом задач является Vue Router.

Как всегда, код этого руководства можно найти на GitHub.

Предпосылки

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

  • Базовые знания HTML, CSS, JavaScript и Vue. Если вы знаете, как визуализировать что-либо на странице с помощью Vue, вы сможете следовать за ним. Немного знаний об API также могут помочь.
  • На вашем компьютере установлены Node.js и Vue CLI. В этом руководстве мы будем использовать Vue 3, поэтому убедитесь, что Vue CLI обновлен.

Обзор приложения

Мы собираемся создать приложение Pokedex. В нем будет три страницы:

  • Страница со списком покемонов. Это страница по умолчанию, на которой перечислены все 151 оригинальный покемон. Это страница по умолчанию, на которой перечислены все 151 оригинальный покемон
  • Страница покемонов. Здесь мы отображаем основные детали, такие как тип и описание. Здесь мы отображаем основные детали, такие как тип и описание
  • Страница сведений о покемонах. Здесь мы отображаем цепочку эволюции, способности и ходы. десь мы отображаем цепочку эволюции, способности и х

Настройка приложения

Создайте новое приложение Vue с помощью Vue CLI:

vue create poke-vue-router

Выберите Vue 3 из перечисленных вариантов:

Выберите Vue 3 из перечисленных вари

Как только это будет сделано, перейдите в папку проекта и установите нужные нам библиотеки:

cd poke-vue-router
npm install vue-router@4 axios

Обратите внимание, что мы используем Vue Router 4 вместо 3, что является результатом по умолчанию, который отображается при поиске в Google. Это в next.router.vuejs.orgотличие от router.vuejs.org. Мы используем Axios для запроса PokeAPI v2.

На этом этапе рекомендуется запустить проект, чтобы убедиться, что приложение Vue по умолчанию работает:

npm run serve

Зайдите http://localhost:8080/ в свой браузер и проверьте, запущено ли приложение Vue по умолчанию. Должно появиться что-то вроде этого:

свой браузер и проверьте, запущено ли приложение Vue по умолчанию

Далее вам нужно добавить sass-loaderкак зависимость разработчика. Для целей этого руководства лучше всего установить ту же версию, что и я. Это потому, что на момент написания последняя версия несовместима с Vue 3:

npm install sass-loader@10.1.1 --save-dev

Вам также необходимо установить node-sassпо той же причине, что и выше. Лучше придерживаться той же версии, что и моя:

npm install node-sass@4.14.1 --save

Примечание: если установка Sass таким способом у вас не работает, вы также можете выбрать вручную выбрать функции при создании приложения Vue с помощью интерфейса командной строки. Затем выберите препроцессоры CSS и выберите Sass / SCSS (с dart-sass).

Создание приложения

Теперь мы готовы приступить к созданию приложения. По мере продвижения помните, что корневой каталог — это srcпапка.

Начните с обновления main.jsфайла. Здесь мы импортируем корневой компонент App.vueи router/index.jsфайл, в котором мы объявляем все, что связано с маршрутизацией:

// main.js

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";

const app = createApp(App);
app.use(router);
app.mount("#app");

Настройка роутера

В App.vueфайле используйте router-viewкомпонент, предоставленный Vue Router. Это самый верхний компонент, используемый Vue Router, который отображает соответствующий компонент для текущего пути, посещаемого пользователем:

// App.vue
<template>
  <div id="app">
    <router-view />
  </div>
</template>

<script>
export default {
  name: "App",
};
</script>

Затем создайте новый router/index.jsфайл и добавьте следующее. Чтобы создать роутер, нам нужно извлечь createRouterи createWebHistoryиз Vue Router. createRouterпозволяет нам создать новый экземпляр маршрутизатора, одновременно createWebHistoryсоздавая историю HTML5, которая по сути является оболочкой для History API. Это позволяет Vue Router манипулировать адресом в адресной строке, когда мы перемещаемся между страницами:

// router/index.js
import { createRouter, createWebHistory } from "vue-router";

Ниже импортируйте все страницы, которые мы будем использовать:

import PokemonList from "../views/PokemonList.vue";

Вью маршрутизатор требует массив объектов, содержащих path, nameи в componentкачестве его свойств:

  • path: это шаблон, который вы хотите сопоставить. В приведенном ниже коде мы ищем корневой путь. Таким образом, если пользователь пытается получить доступ http://localhost:8000, этот шаблон совпадает.
  • name: имя страницы. Это уникальный идентификатор страницы, который используется, когда вы хотите перейти на эту страницу с других страниц.
  • component: компонент, который вы хотите отобразить, когда он pathсовпадает с URL-адресом, к которому получил доступ пользователь.
const routes = [
  {
    path: "/",
    name: "PokemonList",
    component: PokemonList,
  },
];

Наконец, создайте экземпляр маршрутизатора, предоставив объект, содержащий historyи, routesв createRouter:

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

export default router;

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

Создание страницы

Создание страницы действительно не требует специального кода. Итак, если вы знаете, как создать собственный компонент во Vue, вы сможете создать страницу для использования Vue Router.

Создайте views/PokemonList.vueфайл и добавьте код ниже. В этом файле мы используем специальный Listкомпонент для визуализации списка покемонов. Единственное, что нам действительно нужно сделать, это предоставить данные для использования Listкомпонентом. Мы делаем запрос к PokeAPI после того, как компонент смонтирован. Мы не хотим, чтобы список становился слишком большим, поэтому мы ограничиваем результаты до 151 оригинального покемона. Как только мы получим результаты, мы просто присваиваем их данным компонента items. Это, в свою очередь, обновит Listкомпонент:

<template>
  <List :items="items" />
</template>

<script>
import axios from "axios";
import List from "../components/List.vue";

export default {
  name: "PokemonList",
  data() {
    return {
      items: null,
    };
  },
  mounted() {
    axios.get(`https://pokeapi.co/api/v2/pokemon?limit=151`).then((res) => {
      if (res.data && res.data.results) {
        this.items = res.data.results;
      }
    });
  },
  components: {
    List,
  },
};
</script>

Вот код Listкомпонента. Компоненты хранятся в componentsкаталоге, поэтому создайте components/List.vueфайл и добавьте следующее:

 

<template>
  <div v-if="items">
    <router-link
      :to="{ name: 'Pokemon', params: { name: row.name } }"
      class="link"
      v-for="row in items"
      :key="row.name"
    >
      <div class="list-item">
        {{ row.name }}
      </div>
    </router-link>
  </div>
</template>

<script>
export default {
  name: "List",
  props: {
    items: {
      type: Array,
    },
  },
};
</script>

<style lang="scss" scoped>
@import "../styles/list.scss";
</style>

Вы можете проверить код styles/list.scssфайла в репозитории GitHub.

Читайте также:  Как использовать Bootstrap с React?

На этом этапе вы можете просмотреть изменения в браузере. Только вместо этого вы получите следующую ошибку:

Это потому, что Vue пытается сгенерировать ссылку на страницу Pokemon

Это потому, что Vue пытается сгенерировать ссылку на страницу Pokemon, но ее еще нет. Vue CLI достаточно умен, чтобы предупредить вас об этом. Вы можете временно решить эту проблему, используя <div> вместо шаблона components/List.vueфайла:

<template>
  <div v-if="items">
    <div v-for="row in items" :key="row.name">{{ row.name }}</div>
  </div>
</template>

После этого вы сможете увидеть список покемонов. Не забудьте изменить это позже, когда мы добавим страницу Pokemon.

Декларативная навигация

С Vue Router вы можете перемещаться двумя способами: декларативно и программно. Декларативная навигация во многом аналогична тому, что мы делаем с тегом привязки в HTML. Вы просто указываете, куда вы хотите перейти по ссылке. С другой стороны, программная навигация выполняется путем явного вызова Vue Router для перехода на определенную страницу при выполнении действия пользователя (например, нажатия кнопки кнопки).

Давайте быстро разберемся, как это работает. Для навигации нужно использовать router-linkкомпонент. Единственное свойство, которое для этого требуется, — это :to. Это объект, содержащий nameстраницу, к которой вы хотите перейти, и необязательный paramsобъект для указания параметров, которые вы хотите передать странице. В этом случае мы передаем имя покемона:

<router-link
  :to="{ name: 'Pokemon', params: { name: row.name } }"
  class="link"
  v-for="row in items"
  :key="row.name"
>
  <div class="list-item">
    {{ row.name }}
  </div>
</router-link>

Чтобы наглядно представить, как это работает, вам нужно знать узор, используемый на Pokemonэкране. Вот как это выглядит следующим образом : /pokemon/:name. :nameпредставляет nameпереданный вами параметр. Например, если пользователь хочет просмотреть Пикачу, URL-адрес будет выглядеть так http://localhost:8000/pokemon/pikachu. Мы вернемся к этому более подробно в ближайшее время.

Параметры маршрута

Мы уже видели, как мы можем сопоставить определенные шаблоны для наших маршрутов, но мы еще не рассмотрели, как мы можем передавать пользовательские параметры. Мы вкратце видели это в router-linkпредыдущем примере.

Также мы будем использовать следующую страницу ( Pokemon), чтобы проиллюстрировать, как параметры маршрута работают в Vue Router. Для этого все, что вам нужно сделать, это префикс имени параметра с помощью двоеточия ( :). В приведенном ниже примере мы хотим передать имя покемона, поэтому мы добавили :name. Это означает, что если мы хотим перейти к этому конкретному маршруту, нам нужно передать значение для этого параметра. Как мы видели в router-linkпримере ранее, здесь мы передаем имя покемона:

// router/index.js
import PokemonList from "../views/PokemonList.vue";

import Pokemon from "../views/Pokemon"; // add this

const routes = [
  {
    path: "/",
    name: "PokemonList",
    component: PokemonList,
  },
  // add this:
  {
    path: "/pokemon/:name",
    name: "Pokemon",
    component: Pokemon,
  }
]

Вот код Pokemonстраницы ( views/Pokemon.vue). Как и на странице PokemonList ранее, мы делегируем задачу отрисовки пользовательского интерфейса отдельному компоненту BasicDetails. Когда компонент смонтирован, мы делаем запрос к /pokemonконечной точке API. Чтобы передать имя покемона в качестве параметра маршрута, мы используем this.$route.params.name. Свойство, к которому мы получаем доступ, должно совпадать с именем, которое вы дали параметру в router/index.jsфайле. В данном случае это name. Если вы использовали /pokemon/:pokemon_nameдля pathвместо этого, вы к нему доступ this.$route.params.pokemon_name:

<template>
  <BasicDetails :pokemon="pokemon" />
</template>
<script>
import axios from "axios";
import BasicDetails from "../components/BasicDetails.vue";

export default {
  name: "Pokemon",
  data() {
    return {
      pokemon: null,
    };
  },
  mounted() {
    const pokemon_name = this.$route.params.name;

    axios
      .get(`https://pokeapi.co/api/v2/pokemon/${pokemon_name}`)
      .then((res) => {
        const data = res.data;

        axios
          .get(`https://pokeapi.co/api/v2/pokemon-species/${pokemon_name}`)
          .then((res) => {
            Object.assign(data, {
              description: res.data.flavor_text_entries[].flavor_text,
              specie_id: res.data.evolution_chain.url.split("/")[6],
            });

            this.pokemon = data;
          });
      });
  },
  components: {
    BasicDetails,
  },
};
</script>

Вот код для BasicDetailsкомпонента ( components/BasicDetails.vue):

<template>
  <div v-if="pokemon">
    <img :src="pokemon.sprites.front_default" :alt="pokemon.name" />
    <h1>{{ pokemon.name }}</h1>
    <div class="types">
      <div
        class="type-box"
        v-for="row in pokemon.types"
        :key="row.slot"
        v-bind:class="row.type.name.toLowerCase()"
      >
        {{ row.type.name }}
      </div>
    </div>

    <div class="description">
    {{ pokemon.description }}
    </div>

    <a @click="moreDetails" class="link">More Details</a>
  </div>
</template>

<script>
export default {
  name: "BasicDetails",
  props: {
    pokemon: {
      type: Object,
    },
  },

  methods: {
    moreDetails() {
      this.$router.push({
        name: "PokemonDetails",
        params: {
          name: this.pokemon.name,
          specie_id: this.pokemon.specie_id,
        },
      });
    },
  },
};
</script>

<style lang="scss" scoped>
@import "../styles/types.scss";
@import "../styles/pokemon.scss";
</style>

Вы можете проверить код для styles/types.scssи styles/pokemon.scssфайла в репо GitHub.

На этом этапе вы должны снова увидеть изменения в браузере. Вы также можете обновить components/List.vueфайл до его исходного кода, указав router-linkна нем вместо <div>.

Программная навигация

Вы могли заметить, что мы сделали что-то другое в BasicDetailsкомпоненте. На самом деле мы не перешли на PokemonDetailsстраницу с помощью router-link. Вместо этого мы использовали элемент привязки и перехватили его событие щелчка. Так реализована программная навигация. Мы можем получить доступ к роутеру через this.$router. Затем мы вызываем push()метод, который помещает новую страницу в верхнюю часть стека истории. Какая бы страница ни была наверху, маршрутизатор будет отображать ее. Этот метод позволяет вернуться к предыдущей странице, когда пользователь нажимает кнопку «Назад» в браузере, поскольку нажатие на нее просто «выталкивает» текущую страницу поверх стека истории. Этот метод принимает объект, содержащий nameи paramsсвойства, так что это в значительной степени то же самое, вы передаете вtoнедвижимость в router-link:

methods: {
  moreDetails() {
    this.$router.push({
      name: "PokemonDetails",
      params: {
        name: this.pokemon.name,
        specie_id: this.pokemon.specie_id,
      },
    });
  },
},

Вложенные маршруты

Затем обновите файл маршрутизатора, включив в него путь к странице сведений о Pokemon. Здесь мы используем вложенные маршруты для передачи более чем одного настраиваемого параметра. В этом случае мы передаем nameи specie_id:

import Pokemon from "../views/Pokemon";

import PokemonDetails from "../views/PokemonDetails"; // add this

const routes = [
  // ..
  {
    path: "/pokemon/:name",
    // ..
  },

  // add these
  {
    path: "/pokemon/:name/:specie_id/details",
    name: "PokemonDetails",
    component: PokemonDetails,
  },
];

Вот код для PokemonDetailsстраницы ( views/PokemonDetails.vue):

<template>
  <MoreDetails :pokemon="pokemon" />
</template>
<script>
import axios from "axios";
import MoreDetails from "../components/MoreDetails.vue";

export default {
  name: "PokemonDetails",
  data() {
    return {
      pokemon: null,
    };
  },
  mounted() {
    const pokemon_name = this.$route.params.name;

    axios
      .get(`https://pokeapi.co/api/v2/pokemon/${pokemon_name}`)
      .then((res) => {
        const data = res.data;

        axios.get(`https://pokeapi.co/api/v2/evolution-chain/${this.$route.params.specie_id}`)
        .then((res) => {
          let evolution_chain = [res.data.chain.species.name];

          if (res.data.chain.evolves_to.length > 0) {
            evolution_chain.push(
              res.data.chain.evolves_to[0].species.name
            );

            if (res.data.chain.evolves_to.length > 1) {
              const evolutions = res.data.chain.evolves_to.map((item) => {
                return item.species.name;
              }
            );

            evolution_chain[1] = evolutions.join(" | ");
          }

          if (
            res.data.chain.evolves_to[0].evolves_to.length >
            0
          ) {
            evolution_chain.push(res.data.chain.evolves_to[0].evolves_to[0].species.name);
          }

            Object.assign(data, {
              evolution_chain,
            });
          }

          this.pokemon = data;
        });
    });
  },
  components: {
    MoreDetails,
  },
};
</script>

Вот код для MoreDetailsкомпонентов ( components/MoreDetails.vue):

<template>
  <div v-if="pokemon">
    <h1>{{ pokemon.name }}</h1>

    <div v-if="pokemon.evolution_chain" class="section">
      <h2>Evolution Chain</h2>
      <span v-for="(name, index) in pokemon.evolution_chain" :key="name">
        <span v-if="index">-></span>
        {{ name }}
      </span>
    </div>

    <div v-if="pokemon.abilities" class="section">
      <h2>Abilities</h2>

      <div v-for="row in pokemon.abilities" :key="row.ability.name">
        {{ row.ability.name }}
      </div>
    </div>

    <div v-if="pokemon.moves" class="section">
      <h2>Moves</h2>
      <div v-for="row in pokemon.moves" :key="row.move.name">
        {{ row.move.name }}
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "MoreDetails",
  props: {
    pokemon: {
      type: Object,
    },
  },
};
</script>

<style lang="scss" scoped>
@import "../styles/more-details.scss";
</style>

Вы можете просмотреть содержимое styles/more-details.scssфайла в репозитории GitHub.

Читайте также:  Как проверить использование памяти в Kubernetes Pod?

На этом этапе вы можете щелкнуть любое имя покемона и просмотреть подробную информацию об отдельном покемоне. Возможно, вам потребуется перезапустить сервер, чтобы увидеть изменения.

404 page

Мы добавили код для всех страниц. Но что произойдет, если пользователь введет недопустимый URL-адрес в адресную строку браузера? В таких случаях он просто выдаст ошибку или вообще ничего не отобразит. Нам нужно добавить способ перехвата этих запросов, чтобы мы могли отображать страницу «404 не найден».

Для этого откройте файл роутера и импортируйте NotFoundстраницу:

import NotFound from "../views/NotFound";

Маршруты имеют приоритет в соответствии с порядком их добавления в массив маршрутов. Это означает, что те, которые добавляются первыми, первыми сопоставляются с URL-адресом, введенным пользователем в адресной строке. Таким образом, образец для страницы 404 должен быть добавлен в последнюю очередь.

В routesмассив добавьте следующее:

const routes = [
  // ..
  {
    path: "/pokemon/:name/:specie_id/details",
    // ..
  },

  // add this
  {
    path: "/:pathMatch(.*)*",
    name: "NotFound",
    component: NotFound,
  },
];

Знакомо path? Мы используем настраиваемый параметр с именем, pathMatchсоответствующим любому введенному URL. Итак, если пользователь ввел http://localhost:8000/heyили http://localhost:8000/hey/jude, он отобразит NotFoundстраницу.

Это все хорошо. Но что произойдет, если шаблоны над универсальным шаблоном действительно совпадают? Например:

  • http://localhost:8000/pokemon/someinvalidpokemon
  • http://localhost:8000/pokemon/someinvalidpokemon/99999/details

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

Основная проблема с такими запросами заключается в том, что пользователь предполагает, что определенный идентификатор покемона или вида существует, но это не так. Единственный способ проверить — иметь список действительных покемонов. В свой файл маршрутов импортируйте список допустимых покемонов:

import NotFound from "../views/NotFound";

import valid_pokemon from "../data/valid-pokemon.json"; // add this

Вы можете найти этот файл в репозитории GitHub.

Чтобы перехватить такие запросы, Vue Router предоставляет средства навигации. Думайте о них как о «крючках» для процесса навигации, которые позволяют вам выполнять определенные действия до или после того, как Vue Router перешел на определенную страницу. Мы рассмотрим только тот, который выполняется до завершения навигации, так как это позволяет нам перенаправить на другую страницу, если наше условие перехода на эту страницу не соответствует.

Чтобы подключиться к текущему запросу до завершения навигации, мы вызываем beforeEach()метод routerэкземпляра:

const router = createRouter({
  // ..
});

router.beforeEach(async (to) => {
  // next: add the condition for navigating to the 404 page
});

Vue Router передает ему два аргумента:

  • to: местоположение целевого маршрута
  • from: текущее местоположение маршрута

Каждый из них содержит эти свойства. Что нас интересует, так это параметры, поскольку они содержат все параметры, которые пользователь передал в URL-адресе.

Вот как выглядит наше состояние. Сначала мы проверяем, существуют ли параметры, которые мы хотим проверить. Если это так, мы переходим к проверке, действительно ли это. Первое условие соответствует Pokemonстранице. Мы используем valid_pokemonмассив из ранее. Сравниваем с to.params.name, которое содержит имя покемона, переданное пользователем. С другой стороны, второе условие соответствует PokemonDetailsстранице. Здесь мы проверяем идентификатор вида. Поскольку мы хотим сопоставить только оригинальный 101 Pokemon, любой идентификатор, который больше указанного, считается недействительным. Если он соответствует любому из этих условий, мы просто возвращаем путь к странице 404. Если условия не совпадают, он перейдет туда, где изначально предполагалось:

if (
  to.params &&
  to.params.name &&
  valid_pokemon.indexOf(to.params.name) === -1
) {
  return "/404";
}

if (
  (to.params &&
    to.params.name &&
    to.params.specie_id &&
    valid_pokemon.indexOf(to.params.name) === -1 &&
    to.params.specie_id < ) ||
  to.params.specie_id > 101
) {
  return "/404";
}

Вот код для страницы 404 ( views/NotFound.vue):

<template>
  <h1>404 Not Found</h1>
</template>
<script>
export default {
  name: "Not Found",
};
</script>
<style lang="scss" scoped>
@import "../styles/notfound.scss";
</style>

Вы можете просмотреть код styles/notfound.scss файла в репозитории GitHub.

На этом приложение готово! Вы можете попробовать посетить недействительные страницы, и он вернет страницу 404.

Вывод

Вот и все! В этом руководстве вы узнали основы использования Vue Router. Такие вещи, как настройка маршрутизатора, передача пользовательских параметров, переход между страницами и реализация страницы 404, принесут вам долгий путь. Если вы хотите получить какое-то направление, куда двигаться дальше, я рекомендую изучить следующие темы:

  • Передача свойств в компоненты маршрута : позволяет отделить компоненты представления от параметров маршрута. Это дает возможность поменять местами параметры маршрута на свойства, к которым можно получить доступ из компонента. Таким образом, вы можете использовать свои компоненты везде, где их нет $route.params.
  • Переходы : для анимации перехода между страницами.
  • Ленивая загрузка : это скорее улучшение производительности, поэтому сборщик не компилирует коды для всех страниц в одном файле. Вместо этого он будет лениво загружать его, так что браузер загружает код для определенной страницы только тогда, когда это необходимо.
Оцените статью
bestprogrammer.ru
Добавить комментарий