Vue router как передать данные в компонент
Перейти к содержимому

Vue router как передать данные в компонент

  • автор:

# Начало работы

(opens new window) в примерах кода в этом руководстве.

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

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

# HTML

script src="https://unpkg.com/vue@2/dist/vue.js"> script> script src="https://unpkg.com/vue-router@3/dist/vue-router.js"> script> div id="app"> h1>Первое приложение!h1> p>  ` по умолчанию отображается тегом `` --> router-link to="/foo">Перейти к Foorouter-link> router-link to="/bar">Перейти к Barrouter-link> p> router-view>router-view> div> 

# JavaScript

// 0. Если используем модульную систему (например через vue-cli), // импортируем Vue и VueRouter и затем вызываем `Vue.use(VueRouter)`. // 1. Определяем компоненты для маршрутов. // Они могут быть импортированы из других файлов const Foo =  template: '
foo
'
> const Bar = template: '
bar
'
> // 2. Определяем несколько маршрутов // Каждый маршрут должен указывать на компонент. // "Компонентом" может быть как конструктор компонента, созданный // через `Vue.extend()`, так и просто объект с опциями компонента. // Мы поговорим о вложенных маршрутах позднее. const routes = [ path: '/foo', component: Foo >, path: '/bar', component: Bar > ] // 3. Создаём экземпляр маршрутизатора и передаём маршруты в опции `routes` // Вы можете передавать и дополнительные опции, но пока не будем усложнять. const router = new VueRouter( routes // сокращённая запись для `routes: routes` >) // 4. Создаём и монтируем корневой экземпляр приложения. // Убедитесь, что передали экземпляр маршрутизатора в опции // `router`, чтобы позволить приложению знать о его наличии. const app = new Vue( router >).$mount('#app') // Всё, приложение работает! ;)

Внедряя маршрутизатор, мы сможем получить к нему доступ через this.$router , а также к текущему маршруту через this.$route внутри любого компонента:

// Home.vue export default  computed:  username()  // Мы скоро разберём что такое `params` return this.$route.params.username > >, methods:  goBack()  window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/') > > > 

В документации мы будем часто использовать экземпляр router (маршрутизатора). Имейте ввиду, что this.$router в точности то же самое, что и router . Причина, почему используем this.$router заключается в том, что мы не хотим импортировать маршрутизатор в каждом компоненте, в котором потребуется управлять маршрутизацией.

Вы также можете увидеть этот пример вживую здесь

Обратите внимание, что автоматически получает класс .router-link-active при совпадении маршрута. Подробнее об этом можно узнать в справочнике API.

# Передача входных параметров в компоненты маршрута

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

Для разделения компонента от маршрутизатора можно использовать входные параметры ( props ):

Вместо жёсткой связи с $route

const User =  template: '
Пользователь >
'
> const router = new VueRouter( routes: [ path: '/user/:id', component: User > ] >)

Разделяем с помощью входных параметров

const User =  props: ['id'], template: '
Пользователь >
'
> const router = new VueRouter( routes: [ path: '/user/:id', component: User, props: true >, // для маршрутов с именованными представлениями необходимо // указывать опцию `props` для каждого именованного представления: path: '/user/:id', components: default: User, sidebar: Sidebar >, props: default: true, sidebar: false > > ] >)

Это позволяет использовать компонент в любом месте, а также облегчает его повторное использование и тестирование.

# Булево значение

Когда props установлено в значение true , значения route.params будут устанавливаться входными параметрами компонента.

# Объект

Когда props объект, они будут устанавливаться входными параметрами компонента как есть. Полезно, когда входные параметры являются статическими данными.

const router = new VueRouter( routes: [  path: '/promotion/from-newsletter', component: Promotion, props:  newsletterPopup: false > > ] >) 

# Функция

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

const router = new VueRouter( routes: [  path: '/search', component: SearchUser, props: (route) => ( query: route.query.q >) > ] >) 

URL /search?q=vue также передаст в качестве входных параметров в компонент SearchUser .

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

Для более продвинутого использования, смотрите пример

Как передать данные из компонента в корневой компонент при использовании роута (router) во Vue

ситуация в компоненте который подключён с помощью router-link изменяются данные которые надо вернуть в родительский компонент. Не подскажите как это сделать? Что то с имитацией события не получается или я может не так делаю(

Отслеживать
задан 14 авг 2021 в 8:23
495 1 1 золотой знак 4 4 серебряных знака 15 15 бронзовых знаков

Вообще, корневой компонент доступен через свойство $root . Но передача данных в него — в Vue является страшным (пожалуй, даже самым страшным) антипаттерном. Вместо такой передачи можно использовать централизованное управление состоянием, или шину событий.

14 авг 2021 в 21:42

@yar85 Оказалось всё проще, надо в дочернем компоненте как обычно эмитировать событие (emit) а в родительском компоненте (где у нас роутер) вешать прослушиватель этого события на router-view и тогда всё легко передаётся вверх

15 авг 2021 в 16:49

Мммм, кажется понял. Если задача была в передаче данных определенному (какому-то «верхнему») роуту, а не именно в корень $root , то по сути даже $emit становится не нужен — ведь можно обработчик событий роутера и в дочернем компоненте разместить (для реакции на переходы), плюс работать с его ссылкой на экземпляр роутера (ссылка во всех компонентах есть, и доступ к роутеру не требует доп.кода). Или я понял неправильно?

15 авг 2021 в 21:07

Ну когда корневой является непосредственно родителем, то конечно проще)) А в общем и целом, $emit нужен для организации двусторонней связи между родителем и дочерним компонентом без участия глобального стейта и шины событий (то есть, если придет идея чейнить $emit ы для подъема данных — то не надо так делать, ибо это зло с точки зрения Vue-идеологии с ее top->down моделью привязок). Отслеживание переходов и передача в пропсы роутера, тоже хороший вариант (как и глобальный стейт), но это слегка другая концепция (она больше о биндинге чем о состоянии).

17 авг 2021 в 7:40

Сам по себе метод $emit даже можно считать костылем, т.к. по факту, он весьма примитивно компенсирует отсутствие у библиотеки полноценной возможности межкомпонентного двустороннего биндинга (которую реализовать на уровне ее ядра вполне реально, и хз почему это так и не было сделано за все годы существования Vue. Видимо, Эван Ю решил «вроде и так работает, ну и ладно». И хоть хотелось бы более изящного решения, в целом этот курс автора либы можно понять: с точки зрения производительности, чем проще и грязнее — тем лучше).

Как работать с Vue 3 Router

☝ Предполагается, что к моменту прочтения этой статьи вы уже знаете, как создавать простое Vue-приложение. Также предполагается, что приложение открывается по адресу localhost:8080 .

Для чего нужен маршрутизатор

При написании сайта или веб-приложения мы можем использовать обычные гиперссылки. Например, сделать панель навигации так:

Главная Настройки Контакты 

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

Концепция Vue Router

Концепция маршрутизатора сводится к тому, что в зависимости от указанного пути и дополнительных параметров приложение отображает соответствующий контент. Например, наша логика подразумевает, что при переходе в /settings отобразится компонент с настройками, а в /contacts — форма обратной связи.

Давайте создадим простое Vue-приложение, которое реализует такую логику. Для быстрого старта воспользуйтесь шаблоном в CodeSandbox.

Мы намеренно опустим шаги по инициализации проекта, поскольку подразумевается, что с этим вы знакомы.

Для начала установим Vue Router:

npm install --save vue-router 

Добавим в точку входа в приложение main.js следующий код:

import < createApp >from 'vue' import < createRouter, createWebHistory >from 'vue-router' import App from './App.vue' import HomeView from './views/HomeView.vue' const router = createRouter(< routes: [< path: '/', component: HomeView >], history: createWebHistory() >) const app = createApp(App) app.use(router) app.mount('#app') 

Маршруты — это массив объектов, в котором мы описываем правила для отображения компонентов в зависимости от маршрута.

history — это настройка, которая отвечает за механизм поведения Vue Router. Мы указали createWebHistory() , то есть роутер будет использовать History API.

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

  

Если мы откроем приложение в браузере, то увидим страницу, которую описали в HomeView.vue .

�� Изучите Vue.js 3

Научитесь с нуля создавать и стилизовать проект, добавлять анимации в веб-приложение и проводить тестирование.

Иерархия и вложенность маршрутов

Создадим страницу настроек views/SettingsView.vue :

  

Добавим новый объект в массив routes в файле main.js :

import SettingsView from './views/SettingsView.vue' const router = createRouter(< routes: [< path: '/', component: HomeView >, < path: '/settings', component: SettingsView >], history: createWebHistory() >) 

Откроем в браузере страницу []() и увидим только что созданный нами компонент.

Теперь добавим дочерний маршрут для страницы настроек — например, настройки профиля:

  

Укажем это в массиве routes в файле main.js :

import SettingsProfileView from './views/SettingsProfileView.vue' const router = createRouter(< routes: [< path: '/', component: HomeView >, < path: '/settings', component: SettingsView, children: [< path: 'profile', component: SettingsProfileView >] >], history: createWebHistory() >) 

Однако, открыв страницу по маршруту /settings/profile , мы не увидим изменений. Для отображения дочерних маршрутов их родитель (в нашем случае SettingsView.vue ) должен также содержать . Исправим это:

  

Теперь всё работает так, как мы и предполагали.

Навигация между маршрутами

Для привычной навигации по ссылкам необходимо использовать компонент . Он принимает проп :to , который указывает, куда будет вести ссылка. Можно прописать полный путь или параметры маршрута — например, имя и query -парметры, которые мы рассмотрим далее.

Давайте зададим маршрутам имена и посмотрим, как это работает.

const router = createRouter(< routes: [< path: '/', name: 'home', component: HomeView >, < path: '/settings', name: 'settings', component: SettingsView, children: [< path: 'profile', name: 'settings-profile', component: SettingsProfileView >] >], history: createWebHistory() >) 

В компоненте views/SettingsView.vue добавим ссылку на главную страницу:

  

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

Для примера добавим кнопку, открывающую настройки профиля, в компонент views/SettingsView.vue :

   

Теперь, находясь на странице /settings и нажав на кнопку, мы попадаем на /settings/profile и видим надпись «Настройки профиля».

Также добавим панель навигации на главную страницу. Пока что там будет только ссылка на настройки.

Маршрутизатор и Composition API

Vue Router предоставляет два основных Composition API для работы с маршрутами: useRouter и useRoute .

useRouter — используется для получения доступа к самому маршрутизатору. В примере выше мы вызывали useRouter() , чтобы получить объект маршрутизатора.

useRoute — используется для получения текущего маршрута. Рассмотрим его подробнее.

Ранее мы добавили кнопку «Показать настройки профиля», но она не пропадает, даже когда мы открываем эти настройки. Давайте исправим эту ошибку.

   

Теперь блок с кнопкой будет отображаться, только если открыта страница по маршруту, потому что мы дали ей имя — settings — и проверили его в компоненте.

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

При помощи useRoute можно получить доступ к параметрам маршрута.

Создадим новый компонент views/UserView.vue :

   

Компонент предполагает, что текущий маршрут содержит параметр id . Давайте добавим этот идентификатор:

import UserView from './views/UserView.vue' const router = createRouter(< routes: [< path: '/', name: 'home', component: HomeView >, < path: '/settings', name: 'settings', component: SettingsView, children: [< path: 'profile', name: 'settings-profile', component: SettingsProfileView >] >, < path: '/user/:id', name: 'user', component: UserView >], history: createWebHistory() >) 

Запись path вида /user/:id означает, что если мы зайдём на страницу /user/123 , то маршрутизатор рассмотрит 123 как параметр id . Соответственно, если мы откроем /user/123 в браузере, то увидим текст «Пользователь ID: 123».

Добавим также ссылку на пользователя 123 на главной странице.

Страница ошибки «Страница не найдена»

Чтобы создать страницу для 404 ошибки, в конец массива маршрутов положим объект вида:

import NotFoundView from './views/NotFoundView.vue' const router = createRouter(< routes: [< path: '/', name: 'home', component: HomeView >, < path: '/settings' name: 'settings', component: SettingsView, children: [< path: 'profile', name: 'settings-profile', component: SettingsProfileView >] >, < path: '/user/:id', name: 'user', component: UserView >, < path: '/:pathMatch(.*)*', name: '404', component: NotFoundView >], history: createWebHistory() >) 
  

Теперь, если мы зайдём на страницу по пути /whatever или любому несуществующему пути, то увидим надпись «Страница не найдена».

Защищённые маршруты и метаданные

Предположим, нам нужно запретить переход неавторизованных пользователей по маршруту /settings . Обозначим дополнительное поле в объекте — метаданные:

const router = createRouter(< routes: [< path: '/', name: 'home', component: HomeView >, < path: '/settings' name: 'settings', component: SettingsView, children: [< path: 'profile', name: 'settings-profile', component: SettingsProfileView, meta: < requiresAuth: true >>] >, < path: '/user/:id', name: 'user', component: UserView >, < path: '/:pathMatch(.*)*', name: '404', component: NotFoundView >], history: createWebHistory() >) 

Теперь мы сможем обращаться к этому полю, когда оперируем объектом текущего маршрута — например, как в примерах выше, с помощью useRoute() .

Однако чтобы не делать проверку прямо в компонентах, воспользуемся встроенным механизмом Vue Router:

const router = createRouter(< . >) // Для упрощения укажем это в переменной const isAuthenticated = false router.beforeEach((to, from) => < if (to.meta.requiresAuth && !isAuthenticated) < return < name: 'home' >> >) 

В этом примере если неавторизованный пользователь попытается зайти на /settings/profile , выполнится редирект на главную.

Анимация переходов между страницами

☝ Предполагается, что к этому моменту вы уже знакомы с концепцией работы компонента во Vue.

Давайте добавим анимацию смены маршрутов в наше приложение. Откроем файл App.vue и изменим его .

В данном примере мы получаем компонент, который рендерится внутри (в нашем случае — корневого). Затем передаём этот компонент внутрь , который будет вызывать анимацию при смене компонента.

Если вы откроете приложение в браузере и попробуете перейти по страницам, ничего не произойдёт, ведь пока что у не добавлена анимация. Давайте это исправим. Добавим к атрибут name и укажем стили.

  .fade-enter-active, .fade-leave-active < transition: opacity 0.5s ease; >.fade-enter-from, .fade-leave-to 

Заключение

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

Больше материалов

  • Зачем использовать TypeScript
  • Паттерны проектирования
  • Как работать с Redux

«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *