From 6e3a2c59a5c4082727281a557caec496cced44ca Mon Sep 17 00:00:00 2001 From: Alex Sokolov <4497128+Alex-Sokolov@users.noreply.github.com> Date: Fri, 25 May 2018 17:33:33 +0300 Subject: [PATCH 1/7] [RU] Translation moved to VuePress --- docs/.vuepress/config.js | 57 +- docs/.vuepress/public/_redirects | 6 + docs/ru/README.md | 18 + docs/ru/api/README.md | 506 ++++++++++++++++++ docs/ru/guide/README.md | 93 ++++ docs/ru/guide/advanced/data-fetching.md | 110 ++++ docs/ru/guide/advanced/lazy-loading.md | 49 ++ docs/ru/guide/advanced/meta.md | 51 ++ docs/ru/guide/advanced/navigation-guards.md | 152 ++++++ docs/ru/guide/advanced/scroll-behavior.md | 80 +++ docs/ru/guide/advanced/transitions.md | 58 ++ docs/ru/guide/essentials/dynamic-matching.md | 74 +++ docs/ru/guide/essentials/history-mode.md | 138 +++++ docs/ru/guide/essentials/named-routes.md | 31 ++ docs/ru/guide/essentials/named-views.md | 86 +++ docs/ru/guide/essentials/navigation.md | 88 +++ docs/ru/guide/essentials/nested-routes.md | 99 ++++ docs/ru/guide/essentials/passing-props.md | 76 +++ .../ru/guide/essentials/redirect-and-alias.md | 60 +++ docs/ru/installation.md | 44 ++ 20 files changed, 1875 insertions(+), 1 deletion(-) create mode 100644 docs/ru/README.md create mode 100644 docs/ru/api/README.md create mode 100644 docs/ru/guide/README.md create mode 100644 docs/ru/guide/advanced/data-fetching.md create mode 100644 docs/ru/guide/advanced/lazy-loading.md create mode 100644 docs/ru/guide/advanced/meta.md create mode 100644 docs/ru/guide/advanced/navigation-guards.md create mode 100644 docs/ru/guide/advanced/scroll-behavior.md create mode 100644 docs/ru/guide/advanced/transitions.md create mode 100644 docs/ru/guide/essentials/dynamic-matching.md create mode 100644 docs/ru/guide/essentials/history-mode.md create mode 100644 docs/ru/guide/essentials/named-routes.md create mode 100644 docs/ru/guide/essentials/named-views.md create mode 100644 docs/ru/guide/essentials/navigation.md create mode 100644 docs/ru/guide/essentials/nested-routes.md create mode 100644 docs/ru/guide/essentials/passing-props.md create mode 100644 docs/ru/guide/essentials/redirect-and-alias.md create mode 100644 docs/ru/installation.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 5138e4530..b0f4a3626 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -9,7 +9,12 @@ module.exports = { lang: 'zh-CN', title: 'Vue Router', description: 'Vue.js 官方的路由管理器。' - } + }, + '/ru/': { + lang: 'ru', + title: 'Vue Router', + description: 'Официальный маршрутизатор для Vue.js.' + }, }, serviceWorker: true, theme: 'vue', @@ -116,6 +121,56 @@ module.exports = { ] } ] + }, + '/ru/': { + label: 'Русский', + selectText: 'Languages', + editLinkText: 'Изменить эту страницу на GitHub', + nav: [ + { + text: 'Руководство', + link: '/ru/guide/' + }, + { + text: 'Справочник API', + link: '/ru/api/' + }, + { + text: 'История изменений', + link: 'https://github.com/vuejs/vue-router/releases' + } + ], + sidebar: [ + '/ru/installation.md', + '/ru/', + { + title: 'Основы', + collapsable: false, + children: [ + '/ru/guide/', + '/ru/guide/essentials/dynamic-matching.md', + '/ru/guide/essentials/nested-routes.md', + '/ru/guide/essentials/navigation.md', + '/ru/guide/essentials/named-routes.md', + '/ru/guide/essentials/named-views.md', + '/ru/guide/essentials/redirect-and-alias.md', + '/ru/guide/essentials/passing-props.md', + '/ru/guide/essentials/history-mode.md' + ] + }, + { + title: 'Продвинутые темы', + collapsable: false, + children: [ + '/ru/guide/advanced/navigation-guards.md', + '/ru/guide/advanced/meta.md', + '/ru/guide/advanced/transitions.md', + '/ru/guide/advanced/data-fetching.md', + '/ru/guide/advanced/scroll-behavior.md', + '/ru/guide/advanced/lazy-loading.md' + ] + } + ] } } } diff --git a/docs/.vuepress/public/_redirects b/docs/.vuepress/public/_redirects index c1d2f6a95..f387187b2 100644 --- a/docs/.vuepress/public/_redirects +++ b/docs/.vuepress/public/_redirects @@ -11,3 +11,9 @@ /zh-cn/advanced/* /zh/guide/advanced/* /zh-cn/api/* /zh/api/ /zh-cn/* /zh/:splat + +/ru/essentials/getting-started.html /ru/guide/ +/ru/essentials/* /ru/guide/essentials/* +/ru/advanced/* /ru/guide/advanced/* +/ru/api/* /ru/api/ +/ru/* /ru/:splat diff --git a/docs/ru/README.md b/docs/ru/README.md new file mode 100644 index 000000000..17b91a6b7 --- /dev/null +++ b/docs/ru/README.md @@ -0,0 +1,18 @@ +# Введение + +:::tip ПРИМЕЧАНИЕ К ВЕРСИИ +Для пользователей TypeScript, `vue-router@3.0+` требуется `vue@2.5+`, и наоборот. +::: + +Vue Router — официальная библиотека маршрутизации для [Vue.js](https://ru.vuejs.org/). Она глубоко интегрируется с ядром Vue.js, что позволяет создавать SPA-приложения с лёгкостью. Включает следующие возможности: + +- Вложенные маршруты/представления +- Модульная конфигурация маршрутизатора +- Доступ к параметрам маршрута, query, wildcards +- Анимация переходов представлений на основе Vue.js +- Удобный контроль навигации +- Автоматическое проставление активного класса CSS для ссылок +- Режимы работы HTML5 history или хэш, с авто-переключением в IE9 +- Настраиваемое поведение прокрутки страницы + +[Начать знакомство](./guide/) или поиграться с [примерами](https://github.com/vuejs/vue-router/tree/dev/examples) (см. [`README.md`](https://github.com/vuejs/vue-router/) для их запуска). diff --git a/docs/ru/api/README.md b/docs/ru/api/README.md new file mode 100644 index 000000000..5c682c2ef --- /dev/null +++ b/docs/ru/api/README.md @@ -0,0 +1,506 @@ +--- +sidebar: auto +--- + +# Справочник API + +## `` + +`` — это компонент предназначенный для навигации пользователя в приложении с клиентской маршрутизацией. Путь назначения указывается с помощью входного параметра `to`. По умолчанию рендерится в тег `` с корректным значением `href`, но может быть сконфигурирован входным параметром `tag`. Кроме того, ссылка автоматически получает активный класс CSS при переходе на путь назначения. + +`` предпочтительнее жёстко закодированного `` по следующим причинам: + +- Он работает одинаково вне зависимости от режима навигации (HTML5 history или хэши), поэтому если вы решите переключить режим, или маршрутизатор для совместимости переключится обратно в режим хэша в IE9, ничего не потребуется изменять. + +- В режиме HTML5 history, `router-link` будет перехватывать событие click, чтобы браузер не пытался перезагрузить страницу. + +- При использовании опции `base` в режиме HTML5 history mode, вам не потребуется добавлять её в URL входного параметра `to`. + +### Применение активного класса к внешнему элементу + +Иногда может потребоваться, чтобы активный класс применялся к внешнему элементу, а не к тегу ``, в этом случае вы можете отобразить внешний элемент с помощью `` и обернуть содержимое тегом `` внутри: + +``` html + + /foo + +``` + +В этом случае `` будет фактической ссылкой (и получит правильный `href`), но активный класс будет применён к внешнему `
  • `. + +## Входные параметры `` + +### to + +- тип: `string | Location` +- обязательный + + Определяет итоговый маршрут ссылки. При нажатии, значение входного параметра `to` будет передано в `router.push()` — поэтому это значение может быть как строкой, так и объектом описывающим маршрут. + + ``` html + + Home + + Home + + + Home + + + Home + + + Home + + + User + + + Register + ``` + +### replace + +- тип: `boolean` +- по умолчанию: `false` + + Установка входного параметра `replace` вызовет `router.replace()` вместо `router.push()` при нажатии, поэтому навигация не оставит записи в истории переходов. + + ``` html + + ``` + +### append + +- тип: `boolean` +- по умолчанию: `false` + + Установка входного параметра `append` будет всегда добавлять относительный путь к текущему. Например, если мы переходим от `/a` к относительной ссылке `b`, то без `append` мы получим адрес `/b`, а вместе с `append` мы получим `/a/b`. + + ``` html + + ``` + +### tag + +- тип: `string` +- по умолчанию: `"a"` + + Иногда мы хотим чтобы `` отображался другим тегом, например `
  • `. В таком случае мы можем использовать входной параметр `tag`, чтобы указать нужный тег, и он всё равно будет прослушивать события click для навигации. + + ``` html + foo + +
  • foo
  • + ``` + +### active-class + +- тип: `string` +- по умолчанию: `"router-link-active"` + + Определение активного класса CSS, который будет применяться когда ссылка активна. Обратите внимание, что значение по умолчанию также можно настроить глобально через опцию `linkActiveClass` конструктора маршрутизатора. + +### exact + +- тип: `boolean` +- по умолчанию: `false` + + Стандартное поведение для определения когда выставлять активный класс основывается на **совпадениях по включению**. Например, `` будет получать этот класс, если текущий путь начинается с `/a/` или `/a`. + + Одним из следствий этого то, что `` будет активным для каждого маршрута! Чтобы заставить ссылку использовать "режим точного соответствия" нужно использовать входной параметр `exact`: + + ``` html + + + ``` + + Ознакомьтесь с другими примерами, объясняющими активный класс ссылок [вживую](https://jsfiddle.net/8xrk1n9f/). + +### event + +- тип: `string | Array` +- по умолчанию: `'click'` + + Определение события (событий), которые будут вызывать навигацию по ссылке. + +### exact-active-class + +- тип: `string` +- по умолчанию: `"router-link-exact-active"` + + Определение активного класса CSS, который будет применяться когда ссылка активна с точным соответствием пути. Обратите внимание, что значение по умолчанию также можно настроить глобально через опцию `linkExactActiveClass` конструктора маршрутизатора. + +## `` + +Компонент `` является функциональным компонентом, который отображает соответствующий данному маршруту компонент. Компоненты отображаемые в `` также могут содержать в шаблоне собственный ``, который будет использован для отображения компонентов вложенных маршрутов. + +Все остальные входные параметры будут переданы в отображаемый компонент, однако чаще всего данные маршрута можно получить из `$route.params` текущего маршрута. + +Поскольку это всего лишь компонент, он работает вместе с `` и ``. При использовании обоих вместе, обязательно используйте `` внутри: + +``` html + + + + + +``` + +## Входные параметры `` + +### name + +- тип: `string` +- по умолчанию: `"default"` + + При наличии имени у ``, оно будет отображать компонент с соответствующим именем в опции `components` сопоставленного маршрута. Обратитесь к разделу [именованных представлений](../guide/essentials/named-views.md) для примера. + +## Опции конструктора Router + +### routes + +- тип: `Array` + + Декларация типа для `RouteConfig`: + + ``` js + declare type RouteConfig = { + path: string; + component?: Component; + name?: string; // для именованных маршрутов + components?: { [name: string]: Component }; // для именованных представлений + redirect?: string | Location | Function; + props?: boolean | string | Function; + alias?: string | Array; + children?: Array; // для вложенных маршрутов + beforeEnter?: (to: Route, from: Route, next: Function) => void; + meta?: any; + + // Добавлено в версии 2.6.0+ + caseSensitive?: boolean; // учитывать регистр при сравнении? (по умолчанию: false) + pathToRegexpOptions?: Object; // настройки path-to-regexp для компиляции regex + } + ``` + +### mode + +- тип: `string` + +- по умолчанию: `"hash" (in browser) | "abstract" (in Node.js)` + +- возможные значения: `"hash" | "history" | "abstract"` + + Определяет режим работы маршрутизатора. + + - `hash`: используется хэш URL для маршрутизации. Работает во всех совместимых с Vue браузерами, включая те, что не поддерживают HTML5 History API. + + - `history`: требует поддержки HTML5 History API и конфигурации сервера. Подробнее в разделе [Режим HTML5 History](../guide/essentials/history-mode.md). + + - `abstract`: работает во всех JavaScript-окружениях, например серверный рендеринг с помощью Node.js. **Маршрутизатор автоматически переключается в этот режим, если не обнаружит API браузера.** + +### base + +- тип: `string` + +- по умолчанию: `"/"` + + Базовый URL приложения. Например, если SPA расположено по пути `/app/`, тогда `base` должно иметь значение `"/app/"`. + +### linkActiveClass + +- тип: `string` + +- по умолчанию: `"router-link-active"` + + Глобальная настройка активного класса по умолчанию для ``. Подробнее смотри в [router-link](#router-link). + +### linkExactActiveClass + +- тип: `string` + +- по умолчанию: `"router-link-exact-active"` + + Глобальная настройка активного класса по умолчанию при точном совпадении маршрута для ``. Подробнее смотри в [router-link](#router-link). + +### scrollBehavior + +- тип: `Function` + + Сигнатура: + + ``` + type PositionDescriptor = + { x: number, y: number } | + { selector: string } | + ?{} + + type scrollBehaviorHandler = ( + to: Route, + from: Route, + savedPosition?: { x: number, y: number } + ) => PositionDescriptor | Promise + ``` + + Подробнее в разделе [Скроллинг](../guide/advanced/scroll-behavior.md). + +### parseQuery / stringifyQuery + +- тип: `Function` + + Предоставление пользовательский функций для парсинга строки запроса / приведения к строке запроса (функции stringify). Переопределяют реализации по умолчанию. + +### fallback + +- тип: `boolean` + +- по умолчанию: `true` + + Определяет, должен ли маршрутизатор возвращаться в режим `hash`, когда браузер не поддерживает `history.pushState`. + + Установка этого параметра в `false` будет вызывать для каждой навигации через `` полное обновление страницы в IE9. Это может быть полезным, когда приложение рендерится на стороне сервера и должно работать в IE9, потому что режим `hash` не работает с серверным рендерингом (SSR). + +## Свойства экземпляра Router + +### router.app + +- тип: `Vue instance` + + Корневой экземпляр Vue, в который внедряется `router`. + +### router.mode + +- тип: `string` + + [Режим](./#mode) работы, используемый маршрутизатором. + +### router.currentRoute + +- тип: `Route` + + Текущий маршрут в виде [объекта Route](#the-route-object). + +## Методы экземпляра Router + +### router.beforeEach +### router.beforeResolve +### router.afterEach + +Сигнатуры: + +``` js +router.beforeEach((to, from, next) => { + /* необходимо вызывать `next` */ +}) + +router.beforeResolve((to, from, next) => { + /* необходимо вызывать `next` */ +}) + +router.afterEach((to, from) => {}) +``` + +Добавляют глобальные навигационные хуки навигации. Подробнее в разделе [Навигационные хуки](../guide/advanced/navigation-guards.md). + +Все три метода возвращают функцию, которая удаляет зарегистрированный хук. + +### router.push +### router.replace +### router.go +### router.back +### router.forward + +Сигнатуры: + +``` js +router.push(location, onComplete?, onAbort?) +router.replace(location, onComplete?, onAbort?) +router.go(n) +router.back() +router.forward() +``` + +Программная навигация к новому URL. Подробнее в разделе [Программная навигация](../guide/essentials/navigation.md). + +### router.getMatchedComponents + +Сигнатура: + +``` js +const matchedComponents: Array = router.getMatchedComponents(location?) +``` + +Возвращает массив компонентов (определение/конструктор, не экземпляры) сопоставленные для указанного адреса или текущего маршрута. В основном это используется для рендеринга на стороне сервера, чтобы выполнить предварительную загрузку данных. + +### router.resolve + +Сигнатура: + +``` js +const resolved: { + location: Location; + route: Route; + href: string; +} = router.resolve(location, current?, append?) +``` + +Обратное разрешение URL. Полученное местоположение в формате, аналогичном используемому в ``. + +- `current` текущий маршрут по умолчанию (в большинстве случаев вам не потребуется это менять) +- `append` позволяет вам добавить путь к маршруту `current` (как например с помощью [`router-link`](#router-link-props)) + +### router.addRoutes + +Сигнатура: + +``` js +router.addRoutes(routes: Array) +``` + +Динамически добавляет дополнительные маршруты в маршрутизатор. Аргумент должен быть массивом маршрутов в таком же формате, как и в опции `routes` конструктора. + +### router.onReady + +Сигнатура: + +``` js +router.onReady(callback, [errorCallback]) +``` + +Этот метод добавляет в очередь коллбэк, который будет вызван когда маршрутизатор завершит начальную навигацию, что означает что будут завершены все асинхронные хуки и будут готовы асинхронные компоненты, связанные с начальным маршрутом. + +Это пригодится при рендеринге на стороне сервера, чтобы обеспечить консистентный результат как на сервере, так и на клиенте. + +Второй аргумент `errorCallback` поддерживается только в версиях 2.4+. Он вызывается, когда исходное разрешение маршрута заканчивается ошибкой (например, не удалось разрешить асинхронный компонент). + +### router.onError + +Сигнатура: + +``` js +router.onError(callback) +``` + +Регистрирует коллбэк, который будет вызван при обнаружении ошибок во время навигации по маршруту. Обратите внимание, что для вызова коллбэка это должен быть один из следующих сценариев: + +- Ошибка произошла синхронно внутри функции маршрута; + +- Ошибка фиксируется и асинхронно обрабатывается с помощью `next(err)` внутри функции навигационного хука; + +- Произошла ошибка при попытке разрешить асинхронный компонент, необходимый для отображения маршрута. + +## Объект Route + +**Объект маршрута (Route)** представляет собой состояние текущего активного маршрута. Он содержит информацию о текущем URL и **записи маршрутов**, совпавшие с ним. + +Объект маршрута иммутабелен. Каждая успешная навигация будет создавать новый объект маршрута. + +Объект маршрута встречается в нескольких местах: + +- Внутри компонентов как `this.$route` + +- Внутри коллбэка при отслеживании изменений `$route` + +- Как возвращаемое значение при вызове `router.match(location)` + +- В качестве двух первых параметров навигационных хуков: + + ``` js + router.beforeEach((to, from, next) => { + // как `to` так и `from` являются объектами маршрута + }) + ``` + +- В качестве двух первых параметров функции `scrollBehavior`: + + ``` js + const router = new VueRouter({ + scrollBehavior (to, from, savedPosition) { + // как `to` так и `from` являются объектами маршрута + } + }) + ``` + +### Свойства объекта Route + +- **$route.path** + + - тип: `string` + + Строка, идентичная пути текущего маршрута, всегда в абсолютном формате, например `"/foo/bar"`. + +- **$route.params** + + - тип: `Object` + + Объект, который содержит пары ключ/значение динамических сегментов маршрута (включая *-сегменты). Если параметров нет, то значением будет пустой объект. + +- **$route.query** + + - тип: `Object` + + Объект, который содержит пары ключ/значение для строки запроса (query string). Например, для пути `/foo?user=1`, мы получим `$route.query.user == 1`. Если строки запроса нет, то значением будет пустой объект. + +- **$route.hash** + + - тип: `string` + + Хэш текущего маршрута (вместе с символом `#`), если присутствует. Если хэша нет, то значением будет пустая строка. + +- **$route.fullPath** + + - тип: `string` + + Полная запись URL-адреса, включая строку запроса и хэш. + +- **$route.matched** + + - тип: `Array` + + Массив, содержащий **записи маршрутов** для всех вложенных сегментов текущего маршрута. Записи маршрутов — это копии объектов из опции `routes` конфигурации (и вложенных массивов `children`): + + ``` js + const router = new VueRouter({ + routes: [ + // объект ниже — это запись маршрута + { path: '/foo', component: Foo, + children: [ + // это — тоже запись маршрута + { path: 'bar', component: Bar } + ] + } + ] + }) + ``` + +Для URL, равного `/foo/bar`, `$route.matched` будет массивом, содержащим копии объектов (клоны), в порядке сортировки от родителя к потомку. + +- **$route.name** + + Имя текущего маршрута, если такое указано. (Подробнее в разделе [Именованные маршруты](../guide/essentials/named-routes.md)) + +- **$route.redirectedFrom** + + Имя маршрута с которого было перенаправление, если такое указано. (Подробнее в разделе [Перенаправления и псевдонимы](../guide/essentials/redirect-and-alias.md)) + +## Интеграция в компоненты + +### Внедряемые в компоненты свойства + +Эти свойства внедряются в каждый дочерний компонент, передавая экземпляр маршрутизатора в корневой экземпляр в качестве опции `router`. + +- **this.$router** + + Экземпляр маршрутизатора. + +- **this.$route** + + Текущий активный [маршрут (Route)](#the-route-object). Это свойство только для чтения и все его свойства иммутабельны, но можно отслеживать их изменение. + +### Добавляемые опции в компонент + +- **beforeRouteEnter** +- **beforeRouteUpdate** +- **beforeRouteLeave** + + Подробнее в разделе [Навигационные хуки компонентов](../guide/advanced/navigation-guards.md#incomponent-guards). diff --git a/docs/ru/guide/README.md b/docs/ru/guide/README.md new file mode 100644 index 000000000..6cbed4a57 --- /dev/null +++ b/docs/ru/guide/README.md @@ -0,0 +1,93 @@ +# Начало работы + +::: tip Примечание +Мы будем использовать синтаксис [ES2015](https://github.com/lukehoban/es6features) в примерах кода в этом руководстве. + +Кроме того, все примеры будут использовать полную сборку Vue, чтобы позволить компиляцию шаблонов на лету. Подробнее о различиях сборок читайте [здесь](https://ru.vuejs.org/v2/guide/installation.md#Runtime-%D0%9A%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%82%D0%BE%D1%80-vs-Runtime-only). +::: + +Создавать одностраничные приложения (SPA) используя Vue + Vue Router очень просто. С помощью Vue.js, мы уже компонуем своё приложение из компонентов. Добавляя Vue Router, мы просто сопоставляем наши компоненты с маршрутами и объясняем Vue Router где их отображать. Вот простой пример: + +## HTML + +``` html + + + +
    +

    Первое приложение!

    +

    + + + + Перейти к Foo + Перейти к Bar +

    + + +
    +``` + +## JavaScript + +``` js +// 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` внутри любого компонента: + +```js +// 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` заключается в том, что мы не хотим импортировать маршрутизатор в каждом компоненте, в котором потребуется управлять маршрутизацией. + +Вы также можете увидеть этот пример вживую [здесь](https://jsfiddle.net/yyx990803/xgrjzsup/). + +Обратите внимание, что `` автоматически получает класс `.router-link-active` при совпадении маршрута. Подробнее об этом можно узнать в [справочнике API](../api/#router-link). diff --git a/docs/ru/guide/advanced/data-fetching.md b/docs/ru/guide/advanced/data-fetching.md new file mode 100644 index 000000000..018761e31 --- /dev/null +++ b/docs/ru/guide/advanced/data-fetching.md @@ -0,0 +1,110 @@ +# Загрузка данных + +Нередко при переходе между маршрутами требуется получить от сервера какие-либо данные. Например, перед отображением профиля пользователя нужно загрузить данные о нём. Этой цели можно достичь двумя различными путями: + +- **Загрузить данные после перехода**: сначала перейти к новому маршруту, затем загрузить данные в хуке жизненного цикла целевого компонента. По мере загрузки данных отобразить индикатор состояния загрузки. + +- **Загрузить данные перед переходом**: загрузить данные в навигационном хуке роутера, и завершить навигацию уже когда они будут получены. + +С технической точки зрения, оба способа годятся — выбор зависит от того, какой UX вы хотите получить. + +## Загрузка данных после перехода + +При использовании этого подхода, мы осуществляем переход и рендеринг целевого компонента сразу же, а данные запрашиваем в хуке `created` компонента. Это позволяет нам отобразить состояние загрузки, пока данные подтягиваются по сети, причём имея возможность сделать это различным образом для разных компонентов. + +Предположим, у нас есть компонент `Post`, которому требуется загрузить с сервера данные, соответствующие id поста из `$route.params.id`: + +``` html + +``` + +``` js +export default { + data () { + return { + loading: false, + post: null, + error: null + } + }, + created () { + // загружаем данные, когда представление создано + // и данные реактивно отслеживаются + this.fetchData() + }, + watch: { + // при изменениях маршрута запрашиваем данные снова + '$route': 'fetchData' + }, + methods: { + fetchData () { + this.error = this.post = null + this.loading = true + // замените `getPost` используемым методом получения данных / доступа к API + getPost(this.$route.params.id, (err, post) => { + this.loading = false + if (err) { + this.error = err.toString() + } else { + this.post = post + } + }) + } + } +} +``` + +## Загрузка данных перед переходом + +Используя этот подход, мы запрашиваем данные до завершения перехода к новому маршруту. Запрос данных выполняется в навигационном хуке `beforeRouteEnter` компонента, который вызывает `next`, когда данные получены: + +``` js +export default { + data () { + return { + post: null, + error: null + } + }, + beforeRouteEnter (to, from, next) { + getPost(to.params.id, (err, post) => { + next(vm => vm.setData(err, post)) + }) + }, + // если путь изменяется, а компонент уже отображён, + // то логика будет немного иной + beforeRouteUpdate (to, from, next) { + this.post = null + getPost(to.params.id, (err, post) => { + this.setData(err, post) + next() + }) + }, + methods: { + setData (err, post) { + if (err) { + this.error = err.toString() + } else { + this.post = post + } + } + } +} +``` + +Пользователь останется на предыдущей странице, пока не загрузятся данные новой. По этой причине мы советуем отображать какой-нибудь индикатор загрузки. Кроме того, если загрузка данных не удастся, следует отобразить глобальное сообщение об ошибке. diff --git a/docs/ru/guide/advanced/lazy-loading.md b/docs/ru/guide/advanced/lazy-loading.md new file mode 100644 index 000000000..757fddff8 --- /dev/null +++ b/docs/ru/guide/advanced/lazy-loading.md @@ -0,0 +1,49 @@ +# Ленивая загрузка маршрутов + +При использовании модульной системы, итоговая JavaScript-сборка может оказаться довольно большой, что негативно отразится на времени загрузки страницы. В некоторых случаях было бы эффективнее разделить компоненты каждого маршрута на отдельные мини-сборки, и подгружать их только при переходе к соответствующему маршруту. + +Совместное использование [асинхронной загрузки компонентов](https://ru.vuejs.org/v2/guide/components.md#Асинхронные-компоненты) Vue и [возможностям по разделению кода](https://webpack.js.org/guides/code-splitting-async/) Webpack делает реализацию ленивой загрузки компонентов в зависимости от маршрутов тривиальной. + +Во-первых, асинхронный компонент можно определить как функцию-фабрику, которая возвращает Promise (который должен разрешиться самим компонентом): + +``` js +const Foo = () => Promise.resolve({ /* определение компонента */ }) +``` + +Во-вторых, с Webpack 2 мы можем использовать синтаксис [динамических импортов](https://github.com/tc39/proposal-dynamic-import) для указания точек разделения кода: + +``` js +import('./Foo.vue') // возвращает Promise +``` + +::: tip Примечание +если вы используете Babel, то необходимо добавить плагин [syntax-dynamic-import](https://babeljs.io/docs/plugins/syntax-dynamic-import/), чтобы Babel смог корректно обработать синтаксис. +::: + +Эти два пункта — всё необходимое, чтобы определить асинхронный компонент, который Webpack автоматически выделит в отдельную мини-сборку: + +``` js +const Foo = () => import('./Foo.vue') +``` + +В конфигурации маршрута ничего менять не нужно, можно использовать `Foo` как обычно: + +``` js +const router = new VueRouter({ + routes: [ + { path: '/foo', component: Foo } + ] +}) +``` + +## Группировка компонентов в одну мини-сборку + +Иногда может понадобиться объединить в одну мини-сборку все компоненты, расположенные по определённому маршруту. Для этого можно указать [имя мини-сборки Webpack](https://webpack.js.org/guides/code-splitting-async/#chunk-names), используя специальный синтаксис комментариев (в версиях Webpack > 2.4): + +``` js +const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue') +const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue') +const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue') +``` + +Webpack сгруппирует все одноимённые асинхронные модули в одной мини-сборке. diff --git a/docs/ru/guide/advanced/meta.md b/docs/ru/guide/advanced/meta.md new file mode 100644 index 000000000..a0ed5b485 --- /dev/null +++ b/docs/ru/guide/advanced/meta.md @@ -0,0 +1,51 @@ +# Метаданные маршрутов + +Вы можете добавить поле `meta` при определении маршрута: + +``` js +const router = new VueRouter({ + routes: [ + { + path: '/foo', + component: Foo, + children: [ + { + path: 'bar', + component: Bar, + // метаданные + meta: { requiresAuth: true } + } + ] + } + ] +}) +``` + +Как получить к нему доступ? + +Прежде всего, каждый объект маршрута в конфигурации `routes` называется **записью маршрута**. Записи маршрутов могут быть вложенными. Поэтому, при совпадении маршрута, потенциально могут быть активированы несколько записей маршрутов. + +Например, для конфигурации выше, URL `/foo/bar` совпадёт как с родительской, так и с дочерней записями маршрутов. + +Все совпавшие записи маршрутов оказываются доступны через объект `$route` (а также через объекты маршрутов в сторожевых хуках), в виде массива `$route.matched`. Таким образом, для проверки метаданных в записях маршрутов нам понадобится обойти `$route.matched` в цикле. + +В качестве примера можно привести проверку метаданных в глобальном навигационном хуке: + +``` js +router.beforeEach((to, from, next) => { + if (to.matched.some(record => record.meta.requiresAuth)) { + // этот путь требует авторизации, проверяем залогинен ли + // пользователь, и если нет, перенаправляем на страницу логина + if (!auth.loggedIn()) { + next({ + path: '/login', + query: { redirect: to.fullPath } + }) + } else { + next() + } + } else { + next() // всегда так или иначе нужно вызвать next()! + } +}) +``` diff --git a/docs/ru/guide/advanced/navigation-guards.md b/docs/ru/guide/advanced/navigation-guards.md new file mode 100644 index 000000000..ea67f99ec --- /dev/null +++ b/docs/ru/guide/advanced/navigation-guards.md @@ -0,0 +1,152 @@ +# Навигационные хуки + +Как следует из названия, навигационные хуки `vue-router` используются для перенаправлений или отмены навигационных переходов. Есть несколько способов внедрить навигационный хук: глобально, для конкретного маршрута, или для конкретного компонента. + +Следует помнить, что **изменение параметров маршрута не вызывает выполнения навигационных хуков enter/leave**. Вы можете добавить [watch на объект `$route`](../essentials/dynamic-matching.md#reacting-to-params-changes) для отслеживания этих изменений, или использовать хук `beforeRouteUpdate`. + +## Глобальные хуки + +Глобальный хук можно зарегистрировать через `router.beforeEach`: + +``` js +const router = new VueRouter({ ... }) + +router.beforeEach((to, from, next) => { + // ... +}) +``` + +Глобальные навигационные хуки вызываются в порядке их создания при каждом навигационном переходе. Допускается асинхронное разрешение хуков — в этом случае переход считается **незавершённым** до тех пор, пока не будут разрешены все хуки. + +В каждый навигационный хук передаётся три параметра: + +- **`to: Route`**: целевой [объект Route](../../api/#the-route-object), к которому осуществляется переход. + +- **`from: Route`**: текущий маршрут, с которого осуществляется переход к новому. + +- **`next: Function`**: функция, вызов которой **разрешает** хук. В зависимости от переданных в `next` аргументов, результатом будет: + + - **`next()`**: переход к следующему хуку в цепочке. Если хуков больше нет, переход считается **подтверждённым**. + + - **`next(false)`**: отмена перехода. Если URL был изменён (вручную пользователем, или кнопкой "назад"), он будет сброшен на соответствующий маршрут `from`. + + - **`next('/')` или `next({ path: '/' })`**: перенаправление на другой маршрут. Текущий переход будет отменён, и процесс начнётся заново для нового маршрута. Вы можете передать любой объект местоположения в `next`, который позволяет вам указывать опции такие как `replace: true`, `name: 'home'` и любой другой параметр используемый во [входном параметре `to` компонента `router-link`](../../api/#to) или [`router.push`](../../api/#router-push) + + - **`next(error)`**: (добавлено в версии 2.4.0+) если аргумент, переданный `next` является экземпляром `Error`, навигация будет прервана и ошибка будет передана в коллбэк, зарегистрированный через [`router.onError()`](../../api/#router-onerror). + +**Убедитесь, что функция `next` будет вызвана, иначе хук никогда не будет разрешён.** + +## Глобальные хуки разрешения перехода + +Вы можете зарегистрировать глобальный хук с помощью `router.beforeResolve`. Это похоже на `router.beforeEach`, с той разницей, что разрешающий хук будет вызван непосредственно перед подтверждением навигации, **после того, как будут разрешены все хуки компонента и асинхронные компоненты для маршрута**. + +## Глобальные хуки завершения перехода + +Можно также зарегистрировать глобальные хуки, вызываемые после завершения перехода. Однако, в отличие от сторожевых хуков, в них не передаётся функция `next`, и на навигацию они повлиять не могут: + +``` js +router.afterEach((to, from) => { + // ... +}) +``` + +## Хуки для конкретных маршрутов + +Навигационные хуки `beforeEnter` можно указать напрямую для конкретного маршрута в его конфигурации: + +``` js +const router = new VueRouter({ + routes: [ + { + path: '/foo', + component: Foo, + beforeEnter: (to, from, next) => { + // ... + } + } + ] +}) +``` + +Эти хуки имеют точно такую же сигнатуру, как и глобальные хуки. + +## Хуки для конкретных компонентов + +Наконец, навигационный хук можно указать и непосредственно в компоненте (том, что указан в конфигурации маршрута), используя следующие опции: + +- `beforeRouteEnter` +- `beforeRouteUpdate` +- `beforeRouteLeave` + +``` js +const Foo = { + template: `...`, + beforeRouteEnter (to, from, next) { + // вызывается до подтверждения пути, соответствующего этому компоненту. + // НЕ ИМЕЕТ доступа к контексту экземпляра компонента `this`, + // так как к моменту вызова экземпляр ещё не создан! + }, + beforeRouteUpdate (to, from, next) { + // вызывается когда маршрут, что рендерит этот компонент изменился, + // но этот компонент будет повторно использован в новом маршруте. + // Например, для маршрута с динамическими параметрами `/foo/:id`, когда мы + // перемещаемся между `/foo/1` и `/foo/2`, экземпляр того же компонента `Foo` + // будет использован повторно, и этот хук будет вызван когда это случится. + // Также имеется доступ в `this` к экземпляру компонента. + }, + beforeRouteLeave (to, from, next) { + // вызывается перед переходом от пути, соответствующего текущему компоненту; + // имеет доступ к контексту экземпляра компонента `this`. + } +} +``` + +Хук `beforeRouteEnter` **НЕ ИМЕЕТ** доступа к `this`, так как к моменту его вызова навигация ещё не подтверждена, а значит и экземпляр компонента ещё не создан. + +Тем не менее, доступ к экземпляру можно получить, передав коллбэк в `next`. Эта функция будет вызвана после подтверждения навигации, а экземпляр компонента будет передан в неё в качестве параметра: + +``` js +beforeRouteEnter (to, from, next) { + next(vm => { + // экземпляр компонента доступен как `vm` + }) +} +``` + +Обратите внимание, что `beforeRouteEnter` — единственный хук, который поддерживает передачу коллбэка в `next`. Для `beforeRouteUpdate` и `beforeRouteLeave`, `this` уже доступен, поэтому передача коллбэка не требуется и поэтому *не поддерживается*: + +```js +beforeRouteUpdate (to, from, next) { + // просто используйте `this` + this.name = to.params.name + next() +} +``` + +**Навигационный хук ухода со страницы** обычно используется для предотвращения случайного ухода пользователя со страницы с несохранёнными изменениями. Навигацию можно отменить вызовом `next(false)`. + +```js +beforeRouteLeave (to, from , next) { + const answer = window.confirm('Вы хотите уйти? У вас есть несохранённые изменения!') + if (answer) { + next() + } else { + next(false) + } +} +``` + +## Полная цепочка обработки навигации + +1. Срабатывание навигации. +2. Вызов leave-хуков в деактивируемых компонентах. +3. Вызов глобальных `beforeEach` хуков. +4. Вызов `beforeRouteUpdate` хука в переиспользуемых компонентах. +5. Вызов `beforeEnter` в конфигурации маршрута. +6. Разрешение асинхронных компонентов для маршрута. +7. Вызов `beforeRouteEnter` в активируемых компонентах. +8. Вызов глобальных `beforeResolve` хуков. +9. Навигация подтверждена. +10. Вызов глобальных `afterEach` хуков. +11. Выполняется обновление DOM. +12. Вызов коллбэков, переданных в `next` в `beforeRouteEnter` хуке с созданными экземплярами. diff --git a/docs/ru/guide/advanced/scroll-behavior.md b/docs/ru/guide/advanced/scroll-behavior.md new file mode 100644 index 000000000..cdb9bdf7e --- /dev/null +++ b/docs/ru/guide/advanced/scroll-behavior.md @@ -0,0 +1,80 @@ +# Поведение прокрутки страницы + +При переходе между страницами в рамках клиентской маршрутизации, можно сохранять позицию прокрутки для каждой записи в истории (что обычно делают браузеры при работе с традиционными приложениями), или же прокручивать страницу наверх. `vue-router` позволяет использовать оба варианта, и даже более того — позволяет полностью настроить поведение прокрутки при навигации. + +**Примечание: эта возможность работает если браузер поддерживает `history.pushState`.** + +При создании экземпляра маршрутизатора, вы можете указать функцию `scrollBehavior`: + +``` js +const router = new VueRouter({ + routes: [...], + scrollBehavior (to, from, savedPosition) { + // возвращаем требуемую позицию прокрутки + } +}) +``` + +Функция `scrollBehavior` получает объекты маршрутов `to` и `from`. В третьем параметре, `savedPosition`, передаётся сохранённая в истории браузера позиция прокрутки (только в случае `popstate`-перехода, вызванного нажатием кнопок вперёд/назад в браузере). + +Функция возвращает объект позиции прокрутки. Он может иметь одну из двух форм: + +- `{ x: number, y: number }` +- `{ selector: string, offset? : { x: number, y: number }}` (offset поддерживается в 2.6.0+) + +Если возвращается пустой объект или значение, приводимое к ложному, прокрутки не будет. + +Например: + +``` js +scrollBehavior (to, from, savedPosition) { + return { x: 0, y: 0 } +} +``` + +Таким образом мы заставим браузер прокручивать к началу каждой открытой страницы. + +Возврат `savedPosition` позволяет эмулировать нативное поведение браузера при использовании кнопок назад/вперёд: + +``` js +scrollBehavior (to, from, savedPosition) { + if (savedPosition) { + return savedPosition + } else { + return { x: 0, y: 0 } + } +} +``` + +Эмулировать поведение "прокрутки к якорю" на странице можно так: + +``` js +scrollBehavior (to, from, savedPosition) { + if (to.hash) { + return { + selector: to.hash + // , offset: { x: 0, y: 10 } + } + } +} +``` + +Можно также использовать [метаданные путей](meta.md) для более сложного управления прокруткой. Полную реализацию этого подхода можно посмотреть в [этом примере](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js). + +## Асинхронная прокрутка + +> Добавлено в версии 2.8.0 + +Можно также вернуть Promise, который разрешится объектом с желаемой позицией прокрутки: + +``` js +scrollBehavior (to, from, savedPosition) { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve({ x: 0, y: 0 }) + }, 500) + }) +} +``` + +Это можно связать с событиями компонента transition на уровне страницы, чтобы реализовать такое поведение прокрутки, которое сочетается с анимациями перехода между страницами, но из-за множества возможных вариантов и комплексности примеров, мы просто предоставляем этот простой пример, чтобы показать где можно разместить собственную реализацию. diff --git a/docs/ru/guide/advanced/transitions.md b/docs/ru/guide/advanced/transitions.md new file mode 100644 index 000000000..44fbe6971 --- /dev/null +++ b/docs/ru/guide/advanced/transitions.md @@ -0,0 +1,58 @@ +# Анимация переходов + +Поскольку `` — это просто динамический компонент, к нему можно применять анимацию перехода с помощью ``: + +``` html + + + +``` + +Всё, [что сказано о `` в документации Vue](https://ru.vuejs.org/v2/guide/transitions.html), применимо и здесь. + +## Анимация переходов для конкретных маршрутов + +Синтаксис выше применяет одну и ту же анимацию перехода для всех маршрутов. Если для различных маршрутов хочется указать разные анимационные эффекты, можно использовать разноимённые `` непосредственно в шаблонах компонентов: + +``` js +const Foo = { + template: ` + +
    ...
    +
    + ` +} + +const Bar = { + template: ` + +
    ...
    +
    + ` +} +``` + +## Динамическая анимация для маршрутов + +Можно также определять анимацию перехода для маршрутов динамически, в зависимости от соотношения между старым и новым маршрутом: + +``` html + + + + +``` + +``` js +// затем, в родительском компоненте, будем следить за переменной `$route`, +// чтобы определить, какой анимационный переход применять +watch: { + '$route' (to, from) { + const toDepth = to.path.split('/').length + const fromDepth = from.path.split('/').length + this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left' + } +} +``` + +Полный пример можно посмотреть [здесь](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js). diff --git a/docs/ru/guide/essentials/dynamic-matching.md b/docs/ru/guide/essentials/dynamic-matching.md new file mode 100644 index 000000000..02d7c5fb1 --- /dev/null +++ b/docs/ru/guide/essentials/dynamic-matching.md @@ -0,0 +1,74 @@ +# Динамические пути + +Очень часто нам требуется сопоставить маршруты с заданным шаблоном с одним и тем же компонентом. Например, у нас может быть компонент `User`, который должен отображаться для всех пользователей, но с разными ID пользователей. Во `vue-router` мы можем использовать динамический сегмент в маршруте, чтобы достичь этого: + +``` js +const User = { + template: '
    Пользователь
    ' +} + +const router = new VueRouter({ + routes: [ + // динамические сегменты начинаются с двоеточия + { path: '/user/:id', component: User } + ] +}) +``` + +Теперь все URL вида `/user/foo` и `/user/bar` будут соответствовать одному маршруту. + +Динамический сегмент обозначается двоеточием `:`. При сопоставлении маршрута, значение динамического сегмента можно получить через `this.$route.params` в каждом компоненте. Теперь мы можем отобразить ID текущего пользователя, обновив шаблон компонента `User`: + +``` js +const User = { + template: '
    Пользователь {{ $route.params.id }}
    ' +} +``` + +Вы можете посмотреть этот пример вживую [здесь](https://jsfiddle.net/yyx990803/4xfa2f19/). + +Может быть несколько динамических сегментов в одном маршруте. Для каждого сегмента появится соответствующее свойство в `$route.params`. Например: + +| Шаблон | Совпадающий путь | $route.params | +|---------|------|--------| +| /user/:username | /user/evan | `{ username: 'evan' }` | +| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: 123 }` | + +Кроме `$route.params`, объект `$route` предоставляют и другую полезную информацию, например `$route.query` (если URL содержит строку запроса), `$route.hash`, и т.д. Подробнее в [справочнике API](../../api/#the-route-object). + +## Отслеживание изменений параметров + +Важно отметить, что при переходе от `/user/foo` к `/user/bar` **будет повторно использован тот же самый экземпляр компонента**. Поскольку оба маршрута указывают на один и тот же компонент, этот подход эффективнее, чем уничтожение и повторное создание экземпляра. **Но это означает, что хуки жизненного цикла компонента при этом вызываться не будут**. + +Чтобы реагировать на изменения параметров маршрута в рамках одного компонента, достаточно просто отслеживать изменения в объекте `$route`: + +``` js +const User = { + template: '...', + watch: { + '$route' (to, from) { + // обрабатываем изменение параметров маршрута... + } + } +} +``` + +Или можно воспользоваться хуком `beforeRouteUpdate`, добавленным в версии 2.2: + +``` js +const User = { + template: '...', + beforeRouteUpdate (to, from, next) { + // обрабатываем изменение параметров маршрута... + // не забываем вызвать next() + } +} +``` + +## Продвинутые возможности сопоставления + +`vue-router` использует [path-to-regexp](https://github.com/pillarjs/path-to-regexp) в качестве движка для проверки совпадения маршрутов, что позволяет задействовать многие продвинутые возможности, включая опциональные динамические сегменты и регулярные выражения. Подробнее об этих продвинутых возможностях можно изучить в [документации библиотеки](https://github.com/pillarjs/path-to-regexp#parameters), а на [примере](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) узнать как использовать их совместно с `vue-router`. + +## Приоритеты при сопоставлении маршрутов + +Иногда один и тот же URL может совпасть с несколькими маршрутами. В таких случаях приоритет определяется порядком определения маршрутов: чем раньше определён маршрут, тем выше у него приоритет. diff --git a/docs/ru/guide/essentials/history-mode.md b/docs/ru/guide/essentials/history-mode.md new file mode 100644 index 000000000..4eeecfb6d --- /dev/null +++ b/docs/ru/guide/essentials/history-mode.md @@ -0,0 +1,138 @@ +# Режим HTML5 History + +По умолчанию `vue-router` работает в режиме _хэша_ — он использует хэш URL для симуляции полного URL-адреса, что позволяет избежать перезагрузки страницы при изменении URL. + +Мы можем обойтись без хэша, используя **режим history**, который работает с API `history.pushState` для достижения той же цели: + +``` js +const router = new VueRouter({ + mode: 'history', + routes: [...] +}) +``` + +При использовании этого URL выглядит естественно, например: `http://oursite.com/user/id`. Прекрасно! + +Возникает, однако, и проблема: поскольку наше приложение — одностраничное, не сконфигурировав соответствующим образом сервер мы заставим пользователей получать ошибку 404, если они перейдут по `http://oursite.com/user/id` напрямую. Вот это уже прекрасным не назвать. + +Не спешите расстраиваться: всё, что нужно — единственная "резервная" запись в конфигурации сервера. Если URL не совпадает ни с одним статическим файлом, сервер должен просто отдать `index.html`, в котором и живёт наше приложение. И снова, прекрасно! + +## Примеры конфигурирования серверов + +#### Apache + +```apache + + RewriteEngine On + RewriteBase / + RewriteRule ^index\.html$ - [L] + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule . /index.html [L] + +``` + +Вместо `mod_rewrite`, вы также можете использовать [`FallbackResource`](https://httpd.apache.org/docs/2.2/mod/mod_dir.html#fallbackresource). + +#### nginx + +```nginx +location / { + try_files $uri $uri/ /index.html; +} +``` + +#### Node.js + +```js +const http = require('http') +const fs = require('fs') +const httpPort = 80 + +http.createServer((req, res) => { + fs.readFile('index.htm', 'utf-8', (err, content) => { + if (err) { +      console.log('Невозможно открыть файл "index.htm".) + } + + res.writeHead(200, { + 'Content-Type': 'text/html; charset=utf-8' + }) + + res.end(content) + }) +}).listen(httpPort, () => { + console.log('Сервер запущен на: http://localhost:%s', httpPort) +}) +``` + +#### Node.js c использованием Express + +При использовании Node.js/Express, мы рекомендуем пользоваться [connect-history-api-fallback middleware](https://github.com/bripkens/connect-history-api-fallback). + +#### Internet Information Services (IIS) + +1. Установить [IIS UrlRewrite](https://www.iis.net/downloads/microsoft/url-rewrite) +2. Создать файл `web.config` в корневом каталоге вашего сайта со следующим содержимым: + +```xml + + + + + + + + + + + + + + + + + +``` + +#### Caddy + +``` +rewrite { + regexp .* + to {path} / +} +``` + +#### Хостинг Firebase + +Добавьте в файл `firebase.json`: + +``` +{ + "hosting": { + "public": "dist", + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} +``` + +## Предостережение + +При таком подходе возникает одно неприятное последствие: ваш сервер больше не будет сообщать об ошибках 404, поскольку все найденные пути теперь возвращают `index.html`. Чтобы обойти эту проблему, вы должны реализовать специальный маршрут в своём приложении Vue, чтобы показывать страницу 404: + +``` js +const router = new VueRouter({ + mode: 'history', + routes: [ + { path: '*', component: NotFoundComponent } + ] +}) +``` + +В качестве альтернативы, если вы используете сервер Node.js, вы можете реализовать fallback, используя маршрутизатор на стороне сервера, чтобы сопоставлять поступающие URL и отвечать с помощью 404, если не найдено сопоставлений маршруту. Ознакомьтесь с [руководством по серверному рендерингу Vue.js](https://ssr.vuejs.org/ru/) для получения дополнительной информации. diff --git a/docs/ru/guide/essentials/named-routes.md b/docs/ru/guide/essentials/named-routes.md new file mode 100644 index 000000000..6552c6862 --- /dev/null +++ b/docs/ru/guide/essentials/named-routes.md @@ -0,0 +1,31 @@ +# Именованные маршруты + +Иногда удобнее определять маршрут по имени, особенно при привязке к маршруту или выполнении навигации. Вы можете указать для маршрута имя в опции `routes` при создании экземпляра маршрутизатора: + +``` js +const router = new VueRouter({ + routes: [ + { + path: '/user/:userId', + name: 'user', + component: User + } + ] +}) +``` + +Чтобы создать ссылку на именованный маршрут, вы можете передать объект во входной параметр `to` компонента `router-link`: + +``` html +Пользователь +``` + +Тот же самый объект можно использовать и для программного вызова `router.push()`: + +``` js +router.push({ name: 'user', params: { userId: 123 }}) +``` + +В обоих случаях в результате переход будет происходить на путь `/user/123`. + +Полный пример можно посмотреть [здесь](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js). diff --git a/docs/ru/guide/essentials/named-views.md b/docs/ru/guide/essentials/named-views.md new file mode 100644 index 000000000..66a5831a8 --- /dev/null +++ b/docs/ru/guide/essentials/named-views.md @@ -0,0 +1,86 @@ +# Именованные представления + +Иногда вам необходимо отображать сразу несколько представлений, а не вкладывать одно из них в другое — например, при создании шаблона с представлением `sidebar` для боковой панели и представлением `main` для основного содержимого. В этой ситуации будет удобно использовать именованные представления. Вместо указания единственного ``, можно использовать несколько, присвоив каждому собственное имя. Безымянный `router-view` автоматически получает имя `default`. + +``` html + + + +``` + +При использовании нескольких представлений, вместо единственного компонента при описании пути необходимо указывать объект. Убедитесь, что в ключе `components` используете окончание множественного числа (`s`): + +``` js +const router = new VueRouter({ + routes: [ + { + path: '/', + components: { + default: Foo, + a: Bar, + b: Baz + } + } + ] +}) +``` + +Рабочую демонстрацию этого примера можно найти [здесь](https://jsfiddle.net/posva/6du90epg/). + +## Вложенные именованные представления + +Возможно и создание более сложных шаблонов, используя именованные представления с вложенными представлениями. При этом вам также нужно будет именовать используемые вложенные компоненты `router-view`. Разберём на примере панели настроек: + +``` +/settings/emails /settings/profile ++-----------------------------------+ +------------------------------+ +| UserSettings | | UserSettings | +| +-----+-------------------------+ | | +-----+--------------------+ | +| | Nav | UserEmailsSubscriptions | | +------------> | | Nav | UserProfile | | +| | +-------------------------+ | | | +--------------------+ | +| | | | | | | | UserProfilePreview | | +| +-----+-------------------------+ | | +-----+--------------------+ | ++-----------------------------------+ +------------------------------+ +``` + +- `Nav` это просто обычный компонент +- `UserSettings` компонент представления +- `UserEmailsSubscriptions`, `UserProfile`, `UserProfilePreview` вложенные компоненты представлений + +**Примечание**: _Давайте опустим как должен выглядеть HTML/CSS для реализации подобного шаблона и сосредоточимся на используемых компонентах_ + +Секция `