diff --git a/.eslintignore b/.eslintignore index 1521c8b76..2b88bf081 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ dist +*.ts diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 000000000..e4c7570c1 --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1,2 @@ +github: [posva, yyx990803] +open_collective: vuejs diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml new file mode 100644 index 000000000..268578f3f --- /dev/null +++ b/.github/workflows/release-tag.yml @@ -0,0 +1,23 @@ +on: + push: + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +name: Create Release + +jobs: + build: + name: Create Release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@master + - name: Create Release for Tag + id: release_tag + uses: yyx990803/release-tag@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + body: | + Please refer to [CHANGELOG.md](https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md) for details. diff --git a/CHANGELOG.md b/CHANGELOG.md index ba612e2e8..520f3ff13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,47 +1,344 @@ -## [3.0.6](https://github.com/vuejs/vue-router/compare/v3.0.3...v3.0.6) (2019-04-17) +## [3.6.5](https://github.com/vuejs/vue-router/compare/v3.6.4...v3.6.5) (2022-09-06) +### Bug Fixes + +- **types:** Component with 4 generics for Vue 2.6 ([d6064df](https://github.com/vuejs/vue-router/commit/d6064df1112497dac98e4302d81607efdb1a58c6)), closes [#3786](https://github.com/vuejs/vue-router/issues/3786) + +## [3.6.4](https://github.com/vuejs/vue-router/compare/v3.6.3...v3.6.4) (2022-08-25) + +This release fixes some compatibility issues of the new `vue-router/composables` with webpack 4. + +### Features + +- **types:** add composables.d.ts in root ([#3784](https://github.com/vuejs/vue-router/issues/3784)) ([0cf54de](https://github.com/vuejs/vue-router/commit/0cf54de782a0b05692bbe78a7181495b6a35b8d9)) + +## [3.6.3](https://github.com/vuejs/vue-router/compare/v3.6.2...v3.6.3) (2022-08-23) ### Bug Fixes -* revert [#2713](https://github.com/vuejs/vue-router/issues/2713) ([#2723](https://github.com/vuejs/vue-router/issues/2723)) ([ec6eab7](https://github.com/vuejs/vue-router/commit/ec6eab7)), closes [#2719](https://github.com/vuejs/vue-router/issues/2719) +- **build:** export all named exports esm build ([a6647c8](https://github.com/vuejs/vue-router/commit/a6647c8c3d7022f1b702935461c7d234b052ca06)) +- **types:** allow jsx components ([0cb86b3](https://github.com/vuejs/vue-router/commit/0cb86b3865b713201f9db49c7a8d23e9a2876f29)), closes [#3776](https://github.com/vuejs/vue-router/issues/3776) +- **types:** missing NavigationFailureType and isNavigationFailure ([#3777](https://github.com/vuejs/vue-router/issues/3777)) ([9d001dd](https://github.com/vuejs/vue-router/commit/9d001dd0bebdea1e1a8ec2f0c77113b6a2e2b6a3)) +## [3.6.2](https://github.com/vuejs/vue-router/compare/v3.6.1...v3.6.2) (2022-08-23) -## [3.0.5](https://github.com/vuejs/vue-router/compare/v3.0.3...v3.0.5) (2019-04-15) +### Bug Fixes +- **build:** add mjs build ([b4c3940](https://github.com/vuejs/vue-router/commit/b4c39404eff7ae2f657c405d7b0f939ce20cfdec)) +- **types:** missing start location ([1356acb](https://github.com/vuejs/vue-router/commit/1356acb983c5eccb00c5c0ec3f406218ae49a8c1)) + +## [3.6.1](https://github.com/vuejs/vue-router/compare/v3.6.0...v3.6.1) (2022-08-23) ### Bug Fixes -* prevent memory leaks by removing app references ([#2706](https://github.com/vuejs/vue-router/issues/2706)) ([8056105](https://github.com/vuejs/vue-router/commit/8056105)), closes [#2639](https://github.com/vuejs/vue-router/issues/2639) -* push before creating Vue instance ([#2713](https://github.com/vuejs/vue-router/issues/2713)) ([6974a6f](https://github.com/vuejs/vue-router/commit/6974a6f)), closes [#2712](https://github.com/vuejs/vue-router/issues/2712) -* **router-view:** add condition to see whether the tree is inactive (fix [#2552](https://github.com/vuejs/vue-router/issues/2552)) ([#2592](https://github.com/vuejs/vue-router/issues/2592)) ([e6d8fd2](https://github.com/vuejs/vue-router/commit/e6d8fd2)) -* **router-view:** register instance in init hook ([c3abdf6](https://github.com/vuejs/vue-router/commit/c3abdf6)), closes [#2561](https://github.com/vuejs/vue-router/issues/2561) [#2689](https://github.com/vuejs/vue-router/issues/2689) [#2561](https://github.com/vuejs/vue-router/issues/2561) [#2561](https://github.com/vuejs/vue-router/issues/2561) +- **build:** ensure install fn before Vue.use ([0126bcb](https://github.com/vuejs/vue-router/commit/0126bcbfb0e3cb824bfce05090ca018faf02ce5e)), closes [#3772](https://github.com/vuejs/vue-router/issues/3772) +# [3.6.0](https://github.com/vuejs/vue-router/compare/v3.5.4...v3.6.0) (2022-08-22) -## [3.0.4](https://github.com/vuejs/vue-router/compare/v3.0.3...v3.0.4) (2019-04-12) +This release of Vue Router introduces composables from Vue Router 4: +```js +import { useRoute, useRouter, useLink, onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router/composables' +``` + +Since these composables **require Vue 2.7**, they are only exposed under `vue-router/composables` submodule, so it shouldn't affect you if you stay on Vue 2.6 (Note there are no new features or fixes besides the composables in this release). Refer to [the Vue Router 4 API documentation](https://router.vuejs.org/api/#onbeforerouteleave) for details on the composables. + +### Features + +- **types:** useLink() ([77bd0e3](https://github.com/vuejs/vue-router/commit/77bd0e317dd5a9aebfca515f0f28f3284c7d8260)) +- useLink() ([50332e5](https://github.com/vuejs/vue-router/commit/50332e5e93e6aa1194a9e68a60937a6f9e8bcecd)) +- **types:** expose RouterLink and RouterView in d.ts ([cad978a](https://github.com/vuejs/vue-router/commit/cad978a832174aac59cad86fe780f8a64a9754d7)) +- add RouterLink and RouterView to esm ([4511f39](https://github.com/vuejs/vue-router/commit/4511f393334247c9702ed378220bf925cdc09add)) +- add vue 2.7 types ([cba9650](https://github.com/vuejs/vue-router/commit/cba9650e5cbf958c1db9cd259a2e7bfbc28bddbe)) +- onBeforeRouteUpdate onBeforeRouteLeave ([9861c55](https://github.com/vuejs/vue-router/commit/9861c553627f5f34a07ad3ac28e2ed02aab99d47)) +- useRoute and useRouter ([ea35594](https://github.com/vuejs/vue-router/commit/ea355943e097914ae55fa54ccb7df929c901e80d)) + +## [3.5.4](https://github.com/vuejs/vue-router/compare/v3.5.3...v3.5.4) (2022-05-16) ### Bug Fixes -* prevent memory leaks by removing app references ([#2706](https://github.com/vuejs/vue-router/issues/2706)) ([8056105](https://github.com/vuejs/vue-router/commit/8056105)), closes [#2639](https://github.com/vuejs/vue-router/issues/2639) -* **hash:** prevent double decoding ([#2711](https://github.com/vuejs/vue-router/issues/2711)) ([a775fb1](https://github.com/vuejs/vue-router/commit/a775fb1)), closes [#2708](https://github.com/vuejs/vue-router/issues/2708) +- remove whitespace between mulitple slashes ([86d7f1f](https://github.com/vuejs/vue-router/commit/86d7f1fdaa36432f6564309925690ec20bb2981e)), closes [#3743](https://github.com/vuejs/vue-router/issues/3743) +## [3.5.3](https://github.com/vuejs/vue-router/compare/v3.5.2...v3.5.3) (2021-10-26) + +### Bug Fixes + +- clean more than two consecutive slashes ([#3652](https://github.com/vuejs/vue-router/issues/3652)) ([3e3a07e](https://github.com/vuejs/vue-router/commit/3e3a07ee6e7defd6cae75bddcede5a28b0092709)) +- **scrollBehavior:** trigger scroll behavior if same route with hash ([#3592](https://github.com/vuejs/vue-router/issues/3592)) ([57d8042](https://github.com/vuejs/vue-router/commit/57d8042c8b99f92bfe35493b8ae9bba827864bf0)) ### Features -* **esm build:** build ES modules for browser ([#2705](https://github.com/vuejs/vue-router/issues/2705)) ([627027f](https://github.com/vuejs/vue-router/commit/627027f)) +- add constructor hint ([#3626](https://github.com/vuejs/vue-router/issues/3626)) ([28b769b](https://github.com/vuejs/vue-router/commit/28b769b2a07e3bf984c0ec20d6d797291a480e81)) +## [3.5.2](https://github.com/vuejs/vue-router/compare/v3.5.1...v3.5.2) (2021-06-21) -## [3.0.3](https://github.com/vuejs/vue-router/compare/v3.0.2...v3.0.3) (2019-04-08) +### Bug Fixes + +- **history:** stricter check of base in HTML5 ([#3556](https://github.com/vuejs/vue-router/issues/3556)) ([11dd184](https://github.com/vuejs/vue-router/commit/11dd184dc6a872c6399977fa4b7c259225ce4834)) +- **types:** added missing router.match ([#3554](https://github.com/vuejs/vue-router/issues/3554)) ([394a3b6](https://github.com/vuejs/vue-router/commit/394a3b6cce5e395ae4ccf3e2efb0c115d492978c)) + +## [3.5.1](https://github.com/vuejs/vue-router/compare/v3.5.0...v3.5.1) (2021-01-26) + +### Bug Fixes + +- **warn:** only warn if "tag" or "event" is used ([#3458](https://github.com/vuejs/vue-router/issues/3458)) ([b7a31b9](https://github.com/vuejs/vue-router/commit/b7a31b9)), closes [#3457](https://github.com/vuejs/vue-router/issues/3457) + +# [3.5.0](https://github.com/vuejs/vue-router/compare/v3.4.9...v3.5.0) (2021-01-25) + +### Features + +- **link:** exact-path prop ([825328e](https://github.com/vuejs/vue-router/commit/825328e)), closes [#2040](https://github.com/vuejs/vue-router/issues/2040) +- **warn:** warn deprecated addRoutes ([2e41445](https://github.com/vuejs/vue-router/commit/2e41445)) +- expose START_LOCATION ([53b68dd](https://github.com/vuejs/vue-router/commit/53b68dd)), closes [#2718](https://github.com/vuejs/vue-router/issues/2718) +- **link:** deprecate v-slot without custom prop ([ceeda4c](https://github.com/vuejs/vue-router/commit/ceeda4c)) +- **link:** warn deprecated props ([d2cb951](https://github.com/vuejs/vue-router/commit/d2cb951)) +- **router:** add getRoutes ([6bc30aa](https://github.com/vuejs/vue-router/commit/6bc30aa)) +- **types:** add types for getRoutes addRoute ([fb9bb60](https://github.com/vuejs/vue-router/commit/fb9bb60)) +- addRoute as nested route ([ca80c44](https://github.com/vuejs/vue-router/commit/ca80c44)), closes [#1156](https://github.com/vuejs/vue-router/issues/1156) + +## [3.4.9](https://github.com/vuejs/vue-router/compare/v3.4.8...v3.4.9) (2020-11-05) + +### Bug Fixes + +- **encoding:** decode params ([#3350](https://github.com/vuejs/vue-router/issues/3350)) ([63c749c](https://github.com/vuejs/vue-router/commit/63c749c)) + +## [3.4.8](https://github.com/vuejs/vue-router/compare/v3.4.7...v3.4.8) (2020-10-26) + +### Features + +- **scroll:** add behavior support on scrollBehavior ([#3351](https://github.com/vuejs/vue-router/issues/3351)) ([4e0b3e0](https://github.com/vuejs/vue-router/commit/4e0b3e0)) + +## [3.4.7](https://github.com/vuejs/vue-router/compare/v3.4.6...v3.4.7) (2020-10-16) + +### Bug Fixes + +- **matcher:** should try catch decode only ([1f32f03](https://github.com/vuejs/vue-router/commit/1f32f03)) +- **query:** check existing keys ([4b926e3](https://github.com/vuejs/vue-router/commit/4b926e3)), closes [#3341](https://github.com/vuejs/vue-router/issues/3341) + +## [3.4.6](https://github.com/vuejs/vue-router/compare/v3.4.5...v3.4.6) (2020-10-07) + +### Bug Fixes + +- **encoding:** try catch decodes ([607ce2d](https://github.com/vuejs/vue-router/commit/607ce2d)) +- **ssr:** memory leak in poll method ([#2875](https://github.com/vuejs/vue-router/issues/2875)) ([7693eb5](https://github.com/vuejs/vue-router/commit/7693eb5)) +- remove duplicated decodeURIComponent ([#3323](https://github.com/vuejs/vue-router/issues/3323)) ([560d11d](https://github.com/vuejs/vue-router/commit/560d11d)) + +## [3.4.5](https://github.com/vuejs/vue-router/compare/v3.4.4...v3.4.5) (2020-09-26) + +### Bug Fixes + +- **history:** do not call onReady on initial redirection ([a1a290e](https://github.com/vuejs/vue-router/commit/a1a290e)), closes [#3331](https://github.com/vuejs/vue-router/issues/3331) + +## [3.4.4](https://github.com/vuejs/vue-router/compare/v3.4.3...v3.4.4) (2020-09-24) + +### Bug Fixes + +- **abstract:** call afterHooks with go ([4da7021](https://github.com/vuejs/vue-router/commit/4da7021)), closes [#3250](https://github.com/vuejs/vue-router/issues/3250) +- **history:** mark redundant navigation as pending ([893d86b](https://github.com/vuejs/vue-router/commit/893d86b)), closes [#3133](https://github.com/vuejs/vue-router/issues/3133) +- **types:** add missing NavigationFailure types ([fda7067](https://github.com/vuejs/vue-router/commit/fda7067)), closes [#3293](https://github.com/vuejs/vue-router/issues/3293) +- **types:** fix VueRouter.NavigationFailureType ([ecc8e27](https://github.com/vuejs/vue-router/commit/ecc8e27)) + +### Features + +- **history:** Reset history.current when all apps are destroyed ([#3298](https://github.com/vuejs/vue-router/issues/3298)) ([c69ff7b](https://github.com/vuejs/vue-router/commit/c69ff7b)) + +## [3.4.3](https://github.com/vuejs/vue-router/compare/v3.4.2...v3.4.3) (2020-08-11) + +- Revert 4fbaa9f7880276e661227442ef5923131a589210: "fix: keep repeated params in query/hash relative locations" Closes #3289 + +## [3.4.2](https://github.com/vuejs/vue-router/compare/v3.4.1...v3.4.2) (2020-08-07) + +### Bug Fixes + +- **query:** leave object as is ([7b3328d](https://github.com/vuejs/vue-router/commit/7b3328d)), closes [#3282](https://github.com/vuejs/vue-router/issues/3282) +- keep repeated params in query/hash relative locations ([4fbaa9f](https://github.com/vuejs/vue-router/commit/4fbaa9f)) + +## [3.4.1](https://github.com/vuejs/vue-router/compare/v3.4.0...v3.4.1) (2020-08-06) + +### Bug Fixes + +- **query:** remove undefined values ([b952573](https://github.com/vuejs/vue-router/commit/b952573)), closes [#3276](https://github.com/vuejs/vue-router/issues/3276) +- **router:** properly check null and undefined in isSameRoute ([d6546d9](https://github.com/vuejs/vue-router/commit/d6546d9)) + +# [3.4.0](https://github.com/vuejs/vue-router/compare/v3.3.4...v3.4.0) (2020-08-05) + +### Bug Fixes + +- **query:** cast query values to strings (fix [#2131](https://github.com/vuejs/vue-router/issues/2131)) ([#3232](https://github.com/vuejs/vue-router/issues/3232)) ([f0d9c2d](https://github.com/vuejs/vue-router/commit/f0d9c2d)) +- **scroll:** run scrollBehavior on initial load (fix [#3196](https://github.com/vuejs/vue-router/issues/3196)) ([#3199](https://github.com/vuejs/vue-router/issues/3199)) ([84398ae](https://github.com/vuejs/vue-router/commit/84398ae)) +- **types:** add missing `options` property type ([#3248](https://github.com/vuejs/vue-router/issues/3248)) ([83920c9](https://github.com/vuejs/vue-router/commit/83920c9)) + +### Features + +- add vetur tags and attributes ([bf1e1bd](https://github.com/vuejs/vue-router/commit/bf1e1bd)) +- **errors:** capture errors thrown in redirect callback in onError ([#3251](https://github.com/vuejs/vue-router/issues/3251)) ([40e4df7](https://github.com/vuejs/vue-router/commit/40e4df7)), closes [#3201](https://github.com/vuejs/vue-router/issues/3201) [#3201](https://github.com/vuejs/vue-router/issues/3201) [#3201](https://github.com/vuejs/vue-router/issues/3201) +- **errors:** expose `isNavigationFailure` ([8d92dc0](https://github.com/vuejs/vue-router/commit/8d92dc0)) +- **errors:** NavigationDuplicated name for backwards compatibility ([b854a20](https://github.com/vuejs/vue-router/commit/b854a20)) + +## [3.3.4](https://github.com/vuejs/vue-router/compare/v3.3.3...v3.3.4) (2020-06-13) + +### Bug Fixes + +- **matcher:** navigate to same as current location ([62598b9](https://github.com/vuejs/vue-router/commit/62598b9)), closes [#3216](https://github.com/vuejs/vue-router/issues/3216) +- **types:** missing children ([c1df447](https://github.com/vuejs/vue-router/commit/c1df447)), closes [#3230](https://github.com/vuejs/vue-router/issues/3230) + +## [3.3.3](https://github.com/vuejs/vue-router/compare/v3.3.2...v3.3.3) (2020-06-12) + +### Bug Fixes +- **history:** initial redirect call onReady's onSuccess ([4d484bf](https://github.com/vuejs/vue-router/commit/4d484bf)), closes [#3225](https://github.com/vuejs/vue-router/issues/3225) +- update ja docs ([#3214](https://github.com/vuejs/vue-router/issues/3214)) ([c05f741](https://github.com/vuejs/vue-router/commit/c05f741)) + +### Features + +- better wording for navigation redirected failure ([1f3aea6](https://github.com/vuejs/vue-router/commit/1f3aea6)) +- **types:** RouterConfig for multiple components ([#3217](https://github.com/vuejs/vue-router/issues/3217)) ([#3218](https://github.com/vuejs/vue-router/issues/3218)) ([dab86c5](https://github.com/vuejs/vue-router/commit/dab86c5)) + +## [3.3.2](https://github.com/vuejs/vue-router/compare/v3.3.1...v3.3.2) (2020-05-29) ### Bug Fixes -* removes warning resolving asterisk routes ([e224637](https://github.com/vuejs/vue-router/commit/e224637)), closes [#2505](https://github.com/vuejs/vue-router/issues/2505) [#2505](https://github.com/vuejs/vue-router/issues/2505) -* **normalizeLocation:** create a copy with named locations ([#2286](https://github.com/vuejs/vue-router/issues/2286)) ([53cce99](https://github.com/vuejs/vue-router/commit/53cce99)), closes [#2121](https://github.com/vuejs/vue-router/issues/2121) -* **resolve:** use current location if not provided ([#2390](https://github.com/vuejs/vue-router/issues/2390)) ([7ff4de4](https://github.com/vuejs/vue-router/commit/7ff4de4)), closes [#2385](https://github.com/vuejs/vue-router/issues/2385) -* **types:** allow null/undefined in query params ([ca30a75](https://github.com/vuejs/vue-router/commit/ca30a75)), closes [#2605](https://github.com/vuejs/vue-router/issues/2605) +- **errors:** NavigationCanceled with async components ([#3211](https://github.com/vuejs/vue-router/issues/3211)) ([be39ca3](https://github.com/vuejs/vue-router/commit/be39ca3)) +- remove error.stack modification ([#3212](https://github.com/vuejs/vue-router/issues/3212)) ([a0075ed](https://github.com/vuejs/vue-router/commit/a0075ed)) + +## [3.3.1](https://github.com/vuejs/vue-router/compare/v3.3.0...v3.3.1) (2020-05-27) + +### Bug Fixes + +- **errors:** avoid unnecessary log of errors ([2c77247](https://github.com/vuejs/vue-router/commit/2c77247)) + +# [3.3.0](https://github.com/vuejs/vue-router/compare/v3.2.0...v3.3.0) (2020-05-27) + +### Features + +- **errors:** create router errors ([#3047](https://github.com/vuejs/vue-router/issues/3047)) ([4c727f9](https://github.com/vuejs/vue-router/commit/4c727f9)) +- **history:** Remove event listeners when all apps are destroyed. ([#3172](https://github.com/vuejs/vue-router/issues/3172)) ([4c81be8](https://github.com/vuejs/vue-router/commit/4c81be8)), closes [#3152](https://github.com/vuejs/vue-router/issues/3152) [#2341](https://github.com/vuejs/vue-router/issues/2341) +- **url:** call afterEach hooks after url is ensured ([#2292](https://github.com/vuejs/vue-router/issues/2292)) ([1575a18](https://github.com/vuejs/vue-router/commit/1575a18)), closes [#2079](https://github.com/vuejs/vue-router/issues/2079) + +# [3.2.0](https://github.com/vuejs/vue-router/compare/v3.1.6...v3.2.0) (2020-05-19) + +### Bug Fixes + +- **html5:** make base case insensitive ([04a2143](https://github.com/vuejs/vue-router/commit/04a2143)), closes [#2154](https://github.com/vuejs/vue-router/issues/2154) +- check for pushState being a function ([bc41f67](https://github.com/vuejs/vue-router/commit/bc41f67)), closes [#3154](https://github.com/vuejs/vue-router/issues/3154) + +### Features + +- **link:** add aria-current to active links (close [#2116](https://github.com/vuejs/vue-router/issues/2116)) ([#3073](https://github.com/vuejs/vue-router/issues/3073)) ([6ec0ee5](https://github.com/vuejs/vue-router/commit/6ec0ee5)) +- **scroll:** use manual scrollRestoration with scrollBehavior ([#1814](https://github.com/vuejs/vue-router/issues/1814)) ([1261363](https://github.com/vuejs/vue-router/commit/1261363)) +- **types:** NavigationGuardNext ([#2497](https://github.com/vuejs/vue-router/issues/2497)) ([d18c497](https://github.com/vuejs/vue-router/commit/d18c497)) + +## [3.1.6](https://github.com/vuejs/vue-router/compare/v3.1.5...v3.1.6) (2020-02-26) + +### Bug Fixes + +- preserve history state when reloading ([a4ec3e2](https://github.com/vuejs/vue-router/commit/a4ec3e2)) +- **ts:** add null to Route.name ([#3117](https://github.com/vuejs/vue-router/issues/3117)) ([8f831f2](https://github.com/vuejs/vue-router/commit/8f831f2)) +- correctly calculate `path` when `pathMatch` is empty string ([#3111](https://github.com/vuejs/vue-router/issues/3111)) ([38e6ccd](https://github.com/vuejs/vue-router/commit/38e6ccd)), closes [#3106](https://github.com/vuejs/vue-router/issues/3106) + +## [3.1.5](https://github.com/vuejs/vue-router/compare/v3.1.4...v3.1.5) (2020-01-15) + +### Bug Fixes + +- **view:** add passing props to inactive component ([#2773](https://github.com/vuejs/vue-router/issues/2773)) ([0fb1343](https://github.com/vuejs/vue-router/commit/0fb1343)), closes [#2301](https://github.com/vuejs/vue-router/issues/2301) +- **view:** fix deeply nested keep-alive router-views displaying ([#2930](https://github.com/vuejs/vue-router/issues/2930)) ([0c2b1aa](https://github.com/vuejs/vue-router/commit/0c2b1aa)), closes [#2923](https://github.com/vuejs/vue-router/issues/2923) + +## [3.1.4](https://github.com/vuejs/vue-router/compare/v3.1.3...v3.1.4) (2020-01-14) + +### Bug Fixes + +- suppress warning if `pathMatch` is empty ([#3081](https://github.com/vuejs/vue-router/issues/3081)) ([ddc6bc7](https://github.com/vuejs/vue-router/commit/ddc6bc7)), closes [#3072](https://github.com/vuejs/vue-router/issues/3072) +- **link:** correctly warn wrong v-slot usage ([a150291](https://github.com/vuejs/vue-router/commit/a150291)), closes [#3091](https://github.com/vuejs/vue-router/issues/3091) +- **location:** add a copy for params with named locations ([#2802](https://github.com/vuejs/vue-router/issues/2802)) ([2b39f5a](https://github.com/vuejs/vue-router/commit/2b39f5a)), closes [#2800](https://github.com/vuejs/vue-router/issues/2800) [#2938](https://github.com/vuejs/vue-router/issues/2938) [#2938](https://github.com/vuejs/vue-router/issues/2938) + +### Features + +- **history:** preserve existing history.state ([c0d3376](https://github.com/vuejs/vue-router/commit/c0d3376)), closes [#3006](https://github.com/vuejs/vue-router/issues/3006) + +## [3.1.3](https://github.com/vuejs/vue-router/compare/v3.1.2...v3.1.3) (2019-08-30) + +### Bug Fixes + +- **link:** merge event listeners when provided in an anchor ([e0d4dc4](https://github.com/vuejs/vue-router/commit/e0d4dc4)), closes [#2890](https://github.com/vuejs/vue-router/issues/2890) + +### Features + +- **errors:** add stack trace to NavigationDuplicated ([5ef5d73](https://github.com/vuejs/vue-router/commit/5ef5d73)), closes [#2881](https://github.com/vuejs/vue-router/issues/2881) +- warn about root paths without a leading slash ([#2591](https://github.com/vuejs/vue-router/issues/2591)) ([7d7e048](https://github.com/vuejs/vue-router/commit/7d7e048)), closes [#2550](https://github.com/vuejs/vue-router/issues/2550) [#2550](https://github.com/vuejs/vue-router/issues/2550) +## [3.1.2](https://github.com/vuejs/vue-router/compare/v3.1.1...v3.1.2) (2019-08-08) + +### Bug Fixes + +- **types:** prioritize promise based push/replace ([1243e8b](https://github.com/vuejs/vue-router/commit/1243e8b)) + +### Reverts + +- "fix(hash): correctly place query if placed before hash ([#2851](https://github.com/vuejs/vue-router/issues/2851))" ([9b30e4c](https://github.com/vuejs/vue-router/commit/9b30e4c)), closes [#2876](https://github.com/vuejs/vue-router/issues/2876). See more information at https://github.com/vuejs/vue-router/issues/2125#issuecomment-519521424 + +## [3.1.1](https://github.com/vuejs/vue-router/compare/v3.1.0...v3.1.1) (2019-08-06) + +### Bug Fixes + +- **link:** silence back navigations errors ([59b6da3](https://github.com/vuejs/vue-router/commit/59b6da3)) + +# [3.1.0](https://github.com/vuejs/vue-router/compare/v3.0.7...v3.1.0) (2019-08-06) + +### Bug Fixes + +- **abstract history:** allow router.back in abstract mode when 2 consecutive same routes appear in history stack ([#2771](https://github.com/vuejs/vue-router/issues/2771)) ([8910979](https://github.com/vuejs/vue-router/commit/8910979)), closes [#2607](https://github.com/vuejs/vue-router/issues/2607) +- **hash:** correctly place query if placed before hash ([#2851](https://github.com/vuejs/vue-router/issues/2851)) ([b7715dc](https://github.com/vuejs/vue-router/commit/b7715dc)), closes [#2125](https://github.com/vuejs/vue-router/issues/2125) [#2262](https://github.com/vuejs/vue-router/issues/2262) +- **link:** Fix active links when parent link redirects to child ([#2772](https://github.com/vuejs/vue-router/issues/2772)) ([64785a9](https://github.com/vuejs/vue-router/commit/64785a9)), closes [#2724](https://github.com/vuejs/vue-router/issues/2724) +- adapt error to work on IE9 ([527d6d5](https://github.com/vuejs/vue-router/commit/527d6d5)) + +### Features + +- **alias:** warn against redundant aliases ([04a02c0](https://github.com/vuejs/vue-router/commit/04a02c0)), closes [#2461](https://github.com/vuejs/vue-router/issues/2461) [#2462](https://github.com/vuejs/vue-router/issues/2462) +- **scroll:** handle id selectors starting with a number ([799ceca](https://github.com/vuejs/vue-router/commit/799ceca)), closes [#2163](https://github.com/vuejs/vue-router/issues/2163) +- return a promise with push and replace ([#2862](https://github.com/vuejs/vue-router/issues/2862)) ([d907a13](https://github.com/vuejs/vue-router/commit/d907a13)), closes [#1769](https://github.com/vuejs/vue-router/issues/1769) [#1769](https://github.com/vuejs/vue-router/issues/1769) +- scoped slot for link ([e289dde](https://github.com/vuejs/vue-router/commit/e289dde)) +- warn the user for invalid uses of v-slot with Link ([44c63a9](https://github.com/vuejs/vue-router/commit/44c63a9)) + +## [3.0.7](https://github.com/vuejs/vue-router/compare/v3.0.6...v3.0.7) (2019-07-03) + +### Bug Fixes + +- apps loaded from Windows file shares not mapped to network drives ([#2774](https://github.com/vuejs/vue-router/issues/2774)) ([c2c78a3](https://github.com/vuejs/vue-router/commit/c2c78a3)) +- make callback of next in beforeRouterEnter more consistent ([#2738](https://github.com/vuejs/vue-router/issues/2738)) ([8ac478f](https://github.com/vuejs/vue-router/commit/8ac478f)), closes [#2761](https://github.com/vuejs/vue-router/issues/2761) [#2728](https://github.com/vuejs/vue-router/issues/2728) + +## [3.0.6](https://github.com/vuejs/vue-router/compare/v3.0.5...v3.0.6) (2019-04-17) + +### Bug Fixes + +- revert [#2713](https://github.com/vuejs/vue-router/issues/2713) ([#2723](https://github.com/vuejs/vue-router/issues/2723)) ([ec6eab7](https://github.com/vuejs/vue-router/commit/ec6eab7)), closes [#2719](https://github.com/vuejs/vue-router/issues/2719) + +## [3.0.5](https://github.com/vuejs/vue-router/compare/v3.0.4...v3.0.5) (2019-04-15) + +### Bug Fixes + +- push before creating Vue instance ([#2713](https://github.com/vuejs/vue-router/issues/2713)) ([6974a6f](https://github.com/vuejs/vue-router/commit/6974a6f)), closes [#2712](https://github.com/vuejs/vue-router/issues/2712) +- **router-view:** add condition to see whether the tree is inactive (fix [#2552](https://github.com/vuejs/vue-router/issues/2552)) ([#2592](https://github.com/vuejs/vue-router/issues/2592)) ([e6d8fd2](https://github.com/vuejs/vue-router/commit/e6d8fd2)) +- **router-view:** register instance in init hook ([c3abdf6](https://github.com/vuejs/vue-router/commit/c3abdf6)), closes [#2561](https://github.com/vuejs/vue-router/issues/2561) [#2689](https://github.com/vuejs/vue-router/issues/2689) [#2561](https://github.com/vuejs/vue-router/issues/2561) [#2561](https://github.com/vuejs/vue-router/issues/2561) + +## [3.0.4](https://github.com/vuejs/vue-router/compare/v3.0.3...v3.0.4) (2019-04-12) + +### Bug Fixes + +- prevent memory leaks by removing app references ([#2706](https://github.com/vuejs/vue-router/issues/2706)) ([8056105](https://github.com/vuejs/vue-router/commit/8056105)), closes [#2639](https://github.com/vuejs/vue-router/issues/2639) +- **hash:** prevent double decoding ([#2711](https://github.com/vuejs/vue-router/issues/2711)) ([a775fb1](https://github.com/vuejs/vue-router/commit/a775fb1)), closes [#2708](https://github.com/vuejs/vue-router/issues/2708) + +### Features + +- **esm build:** build ES modules for browser ([#2705](https://github.com/vuejs/vue-router/issues/2705)) ([627027f](https://github.com/vuejs/vue-router/commit/627027f)) + +## [3.0.3](https://github.com/vuejs/vue-router/compare/v3.0.2...v3.0.3) (2019-04-08) + +### Bug Fixes +- removes warning resolving asterisk routes ([e224637](https://github.com/vuejs/vue-router/commit/e224637)), closes [#2505](https://github.com/vuejs/vue-router/issues/2505) [#2505](https://github.com/vuejs/vue-router/issues/2505) +- **normalizeLocation:** create a copy with named locations ([#2286](https://github.com/vuejs/vue-router/issues/2286)) ([53cce99](https://github.com/vuejs/vue-router/commit/53cce99)), closes [#2121](https://github.com/vuejs/vue-router/issues/2121) +- **resolve:** use current location if not provided ([#2390](https://github.com/vuejs/vue-router/issues/2390)) ([7ff4de4](https://github.com/vuejs/vue-router/commit/7ff4de4)), closes [#2385](https://github.com/vuejs/vue-router/issues/2385) +- **types:** allow null/undefined in query params ([ca30a75](https://github.com/vuejs/vue-router/commit/ca30a75)), closes [#2605](https://github.com/vuejs/vue-router/issues/2605) ## [3.0.2](https://github.com/vuejs/vue-router/compare/v3.0.1...v3.0.2) (2018-11-23) diff --git a/README.md b/README.md index fdf470672..40cba38ce 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,95 @@ # vue-router [![Build Status](https://img.shields.io/circleci/project/github/vuejs/vue-router/dev.svg)](https://circleci.com/gh/vuejs/vue-router) -> This is vue-router 3.0 which works only with Vue 2.0. For the 1.x router see the [1.0 branch](https://github.com/vuejs/vue-router/tree/1.0). - -### Introduction - -`vue-router` is the official router for [Vue.js](http://vuejs.org). It deeply integrates with Vue.js core to make building Single Page Applications with Vue.js a breeze. Features include: - -- Nested route/view mapping -- Modular, component-based router configuration -- Route params, query, wildcards -- View transition effects powered by Vue.js' transition system -- Fine-grained navigation control -- Links with automatic active CSS classes -- HTML5 history mode or hash mode, with auto-fallback in IE9 -- Customizable Scroll Behavior - -Get started with the [documentation](http://router.vuejs.org), or play with the [examples](https://github.com/vuejs/vue-router/tree/dev/examples) (see how to run them below). +> This is vue-router 3.0 which works only with Vue 2.0. +> - For the 1.x router see the [1.0 branch](https://github.com/vuejs/vue-router/tree/1.0). +> - For Vue Router 4 (for Vue 3) see [vuejs/router](https://github.com/vuejs/router). + +

Supporting Vue Router

+ +Vue Router is part of the Vue Ecosystem and is an MIT-licensed open source project with its ongoing development made possible entirely by the support of Sponsors. If you would like to become a sponsor, please consider: + +- [Become a Sponsor on GitHub](https://github.com/sponsors/posva) +- [One-time donation via PayPal](https://paypal.me/posva) + + + +

Gold Sponsors

+

+ + + + VueJobs + + +

+ +

Silver Sponsors

+

+ + + + VueMastery + + + + + + Prefect + + +

+ +

Bronze Sponsors

+

+ + + + Stanislas Ormières + + + + + + Antony Konstantinidis + + + + + + Storyblok + + + + + + NuxtJS + + +

+ + + +--- + +Get started with the [documentation](http://v3.router.vuejs.org), or play with the [examples](https://github.com/vuejs/vue-router/tree/dev/examples) (see how to run them below). ### Development Setup -``` bash +```bash # install deps -npm install +yarn # build dist files -npm run build +yarn build # serve examples at localhost:8080 -npm run dev +yarn dev # lint & run all tests -npm test +yarn test # serve docs at localhost:8080 -npm run docs +yarn docs ``` ## Releasing @@ -41,7 +97,7 @@ npm run docs - `yarn run release` - Ensure tests are passing `yarn run test` - Build dist files `VERSION= yarn run build` - - Build changelog `yarn run changelod` + - Build changelog `yarn run changelog` - Commit dist files `git add dist CHANGELOG.md && git commit -m "[build $VERSION]"` - Publish a new version `npm version $VERSION --message "[release] $VERSION" - Push tags `git push origin refs/tags/v$VERSION && git push` @@ -61,7 +117,7 @@ Please make sure to read the [Contributing Guide](https://github.com/vuejs/vue/b ## Changelog -Details changes for each release are documented in the [release notes](https://github.com/vuejs/vue-router/releases). +Details changes for each release are documented in the [`CHANGELOG.md file`](https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md). ## Stay In Touch diff --git a/build/build.js b/build/build.js index 09767b9e6..c812b7a6c 100644 --- a/build/build.js +++ b/build/build.js @@ -15,12 +15,14 @@ function build (builds) { let built = 0 const total = builds.length const next = () => { - buildEntry(builds[built]).then(() => { - built++ - if (built < total) { - next() - } - }).catch(logError) + buildEntry(builds[built]) + .then(() => { + built++ + if (built < total) { + next() + } + }) + .catch(logError) } next() @@ -29,19 +31,24 @@ function build (builds) { function buildEntry ({ input, output }) { const { file, banner } = output const isProd = /min\.js$/.test(file) - return rollup.rollup(input) + return rollup + .rollup(input) .then(bundle => bundle.generate(output)) - .then(({ code }) => { + .then(bundle => { + // console.log(bundle) + const code = bundle.output[0].code if (isProd) { - const minified = (banner ? banner + '\n' : '') + terser.minify(code, { - toplevel: true, - output: { - ascii_only: true - }, - compress: { - pure_funcs: ['makeMap'] - } - }).code + const minified = + (banner ? banner + '\n' : '') + + terser.minify(code, { + toplevel: true, + output: { + ascii_only: true + }, + compress: { + pure_funcs: ['makeMap'] + } + }).code return write(file, minified, true) } else { return write(file, code) @@ -52,7 +59,12 @@ function buildEntry ({ input, output }) { function write (dest, code, zip) { return new Promise((resolve, reject) => { function report (extra) { - console.log(blue(path.relative(process.cwd(), dest)) + ' ' + getSize(code) + (extra || '')) + console.log( + blue(path.relative(process.cwd(), dest)) + + ' ' + + getSize(code) + + (extra || '') + ) resolve() } diff --git a/build/configs.js b/build/configs.js index 67371b8e2..4fbfa6d24 100644 --- a/build/configs.js +++ b/build/configs.js @@ -1,12 +1,11 @@ const path = require('path') const buble = require('rollup-plugin-buble') const flow = require('rollup-plugin-flow-no-whitespace') -const cjs = require('rollup-plugin-commonjs') -const node = require('rollup-plugin-node-resolve') +const cjs = require('@rollup/plugin-commonjs') +const node = require('@rollup/plugin-node-resolve').nodeResolve const replace = require('rollup-plugin-replace') const version = process.env.VERSION || require('../package.json').version -const banner = -`/*! +const banner = `/*! * vue-router v${version} * (c) ${new Date().getFullYear()} Evan You * @license MIT @@ -31,27 +30,45 @@ module.exports = [ format: 'cjs' }, { + input: resolve('src/entries/esm.js'), file: resolve('dist/vue-router.esm.js'), format: 'es' }, { + input: resolve('src/entries/esm.js'), + file: resolve('dist/vue-router.mjs'), + format: 'es' + }, + { + input: resolve('src/entries/esm.js'), file: resolve('dist/vue-router.esm.browser.js'), format: 'es', env: 'development', transpile: false }, { + input: resolve('src/entries/esm.js'), file: resolve('dist/vue-router.esm.browser.min.js'), format: 'es', env: 'production', transpile: false + }, + { + input: resolve('src/composables/index.js'), + file: resolve('./composables.mjs'), + format: 'es' + }, + { + input: resolve('src/composables/index.js'), + file: resolve('./composables.js'), + format: 'cjs' } ].map(genConfig) function genConfig (opts) { const config = { input: { - input: resolve('src/index.js'), + input: opts.input || resolve('src/index.js'), plugins: [ flow(), node(), @@ -59,7 +76,8 @@ function genConfig (opts) { replace({ __VERSION__: version }) - ] + ], + external: ['vue'] }, output: { file: opts.file, @@ -70,9 +88,11 @@ function genConfig (opts) { } if (opts.env) { - config.input.plugins.unshift(replace({ - 'process.env.NODE_ENV': JSON.stringify(opts.env) - })) + config.input.plugins.unshift( + replace({ + 'process.env.NODE_ENV': JSON.stringify(opts.env) + }) + ) } if (opts.transpile !== false) { diff --git a/composables.d.ts b/composables.d.ts new file mode 100644 index 000000000..790fbfba8 --- /dev/null +++ b/composables.d.ts @@ -0,0 +1 @@ +export * from './types/composables' diff --git a/composables.js b/composables.js new file mode 100644 index 000000000..18d96d549 --- /dev/null +++ b/composables.js @@ -0,0 +1,257 @@ +/*! + * vue-router v3.6.5 + * (c) 2022 Evan You + * @license MIT + */ +'use strict' + +Object.defineProperty(exports, '__esModule', { value: true }) + +var vue = require('vue') + +// dev only warn if no current instance + +function throwNoCurrentInstance (method) { + if (!vue.getCurrentInstance()) { + throw new Error( + ('[vue-router]: Missing current instance. ' + method + '() must be called inside + + diff --git a/docs/.vuepress/components/HomeSponsorsGroup.vue b/docs/.vuepress/components/HomeSponsorsGroup.vue new file mode 100644 index 000000000..f8e2dab77 --- /dev/null +++ b/docs/.vuepress/components/HomeSponsorsGroup.vue @@ -0,0 +1,43 @@ + + + diff --git a/docs/.vuepress/components/sponsors.json b/docs/.vuepress/components/sponsors.json new file mode 100644 index 000000000..e9c704b39 --- /dev/null +++ b/docs/.vuepress/components/sponsors.json @@ -0,0 +1,44 @@ +{ + "platinum": [], + "gold": [], + "silver": [ + { + "href": "https://www.vuemastery.com/", + "alt": "VueMastery", + "imgSrcLight": "https://posva-sponsors.pages.dev/logos/vuemastery-light.svg", + "imgSrcDark": "https://posva-sponsors.pages.dev/logos/vuemastery-dark.png" + }, + { + "href": "https://www.prefect.io/", + "imgSrcLight": "https://posva-sponsors.pages.dev/logos/prefectlogo-light.svg", + "imgSrcDark": "https://posva-sponsors.pages.dev/logos/prefectlogo-dark.svg", + "alt": "Prefect" + } + ], + "bronze": [ + { + "alt": "Stanislas Ormières", + "href": "https://stormier.ninja", + "imgSrcDark": "https://avatars.githubusercontent.com/u/2486424?u=7b0c73ae5d090ce53bf59473094e9606fe082c59&v=4", + "imgSrcLight": "https://avatars.githubusercontent.com/u/2486424?u=7b0c73ae5d090ce53bf59473094e9606fe082c59&v=4" + }, + { + "alt": "Antony Konstantinidis", + "href": "https://www.vuejs.de", + "imgSrcDark": "https://avatars.githubusercontent.com/u/4183726?u=6b50a8ea16de29d2982f43c5640b1db9299ebcd1&v=4", + "imgSrcLight": "https://avatars.githubusercontent.com/u/4183726?u=6b50a8ea16de29d2982f43c5640b1db9299ebcd1&v=4" + }, + { + "href": "https://storyblok.com", + "imgSrcLight": "https://posva-sponsors.pages.dev/logos/storyblok.png", + "imgSrcDark": "https://posva-sponsors.pages.dev/logos/storyblok.png", + "alt": "Storyblok" + }, + { + "href": "https://nuxtjs.org", + "imgSrcLight": "https://posva-sponsors.pages.dev/logos/nuxt-light.svg", + "imgSrcDark": "https://posva-sponsors.pages.dev/logos/nuxt-dark.svg", + "alt": "Nuxt Labs" + } + ] +} diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index d4f6c8922..79c12f352 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -1,4 +1,4 @@ -module.exports = { +module.exports = ctx => ({ locales: { '/': { lang: 'en-US', @@ -26,20 +26,63 @@ module.exports = { description: 'Vue.js 공식 라우터' }, '/fr/': { - lang: 'fr', - title: 'Vue Router', - description: 'Routeur officiel pour Vue.Js' + lang: 'fr', + title: 'Vue Router', + description: 'Routeur officiel pour Vue.Js' } }, - serviceWorker: true, - theme: 'vue', + head: [ + ['link', { rel: 'icon', href: `/logo.png` }], + [ + 'meta', + { name: 'wwads-cn-verify', content: '7e7757b1e12abcb736ab9a754ffb617a' } + ], + [ + 'link', + { rel: 'apple-touch-icon', href: `/icons/apple-touch-icon-152x152.png` } + ], + [ + 'link', + { + rel: 'mask-icon', + href: '/icons/safari-pinned-tab.svg', + color: '#3eaf7c' + } + ], + [ + 'meta', + { + name: 'msapplication-TileImage', + content: '/icons/msapplication-icon-144x144.png' + } + ] + ], + // theme: '@vuepress/vue', + plugins: [ + [ + '@vuepress/pwa', + { + serviceWorker: true, + updatePopup: true + } + ] + ], themeConfig: { - algolia: { - apiKey: 'f854bb46d3de7eeb921a3b9173bd0d4c', - indexName: 'vue-router', + algolia: ctx.isProd + ? { + appId: 'LI3RW4C4QI', + apiKey: '08e7ef7cd3969442874f0dee9dec34be', + indexName: 'vue-router' + } + : null, + carbonAds: { + carbon: 'CEBICK3I', + custom: 'CEBICK3M', + placement: 'routervuejsorg' }, repo: 'vuejs/vue-router', docsDir: 'docs', + smoothScroll: true, locales: { '/': { label: 'English', @@ -54,6 +97,10 @@ module.exports = { text: 'API Reference', link: '/api/' }, + { + text: 'v3.x', + items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org' }] + }, { text: 'Release Notes', link: 'https://github.com/vuejs/vue-router/releases' @@ -61,7 +108,6 @@ module.exports = { ], sidebar: [ '/installation.md', - '/', { title: 'Essentials', collapsable: false, @@ -86,7 +132,8 @@ module.exports = { '/guide/advanced/transitions.md', '/guide/advanced/data-fetching.md', '/guide/advanced/scroll-behavior.md', - '/guide/advanced/lazy-loading.md' + '/guide/advanced/lazy-loading.md', + '/guide/advanced/navigation-failures.md' ] } ] @@ -104,6 +151,10 @@ module.exports = { text: 'API 参考', link: '/zh/api/' }, + { + text: 'v3.x', + items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org/zh/' }] + }, { text: '更新记录', link: 'https://github.com/vuejs/vue-router/releases' @@ -111,7 +162,6 @@ module.exports = { ], sidebar: [ '/zh/installation.md', - '/zh/', { title: '基础', collapsable: false, @@ -136,7 +186,8 @@ module.exports = { '/zh/guide/advanced/transitions.md', '/zh/guide/advanced/data-fetching.md', '/zh/guide/advanced/scroll-behavior.md', - '/zh/guide/advanced/lazy-loading.md' + '/zh/guide/advanced/lazy-loading.md', + '/zh/guide/advanced/navigation-failures.md' ] } ] @@ -154,6 +205,10 @@ module.exports = { text: 'API リファレンス', link: '/ja/api/' }, + { + text: 'v3.x', + items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org' }] + }, { text: 'リリースノート', link: 'https://github.com/vuejs/vue-router/releases' @@ -161,7 +216,6 @@ module.exports = { ], sidebar: [ '/ja/installation.md', - '/ja/', { title: '基本的な使い方', collapsable: false, @@ -186,7 +240,8 @@ module.exports = { '/ja/guide/advanced/transitions.md', '/ja/guide/advanced/data-fetching.md', '/ja/guide/advanced/scroll-behavior.md', - '/ja/guide/advanced/lazy-loading.md' + '/ja/guide/advanced/lazy-loading.md', + '/ja/guide/advanced/navigation-failures.md' ] } ] @@ -204,6 +259,10 @@ module.exports = { text: 'Справочник API', link: '/ru/api/' }, + { + text: 'v3.x', + items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org' }] + }, { text: 'История изменений', link: 'https://github.com/vuejs/vue-router/releases' @@ -211,7 +270,6 @@ module.exports = { ], sidebar: [ '/ru/installation.md', - '/ru/', { title: 'Основы', collapsable: false, @@ -236,7 +294,8 @@ module.exports = { '/ru/guide/advanced/transitions.md', '/ru/guide/advanced/data-fetching.md', '/ru/guide/advanced/scroll-behavior.md', - '/ru/guide/advanced/lazy-loading.md' + '/ru/guide/advanced/lazy-loading.md', + '/ru/guide/advanced/navigation-failures.md' ] } ] @@ -254,6 +313,10 @@ module.exports = { text: 'API 레퍼런스', link: '/kr/api/' }, + { + text: 'v3.x', + items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org' }] + }, { text: '릴리즈 노트', link: 'https://github.com/vuejs/vue-router/releases' @@ -261,7 +324,6 @@ module.exports = { ], sidebar: [ '/kr/installation.md', - '/kr/', { title: '기본 사용법', collapsable: false, @@ -292,55 +354,58 @@ module.exports = { ] }, '/fr/': { - label: 'Français', - selectText: 'Langues', - editLinkText: 'Editer cette page sur Github', - nav: [ - { - text: 'Guide', - link: '/fr/guide/' - }, - { - text: 'API', - link: '/fr/api/' - }, - { - text: 'Notes de version', - link: 'https://github.com/vuejs/vue-router/releases' - } - ], - sidebar: [ - '/fr/installation.md', - '/fr/', - { - title: 'Essentiels', - collapsable: false, - children: [ - '/fr/guide/', - '/fr/guide/essentials/dynamic-matching.md', - '/fr/guide/essentials/nested-routes.md', - '/fr/guide/essentials/navigation.md', - '/fr/guide/essentials/named-routes.md', - '/fr/guide/essentials/named-views.md', - '/fr/guide/essentials/redirect-and-alias.md', - '/fr/guide/essentials/passing-props.md', - '/fr/guide/essentials/history-mode.md' - ] - }, - { - title: 'Avancés', - collapsable: false, - children: [ - '/fr/guide/advanced/navigation-guards.md', - '/fr/guide/advanced/meta.md', - '/fr/guide/advanced/transitions.md', - '/fr/guide/advanced/data-fetching.md', - '/fr/guide/advanced/scroll-behavior.md', - '/fr/guide/advanced/lazy-loading.md' - ] - } - ] - }, + label: 'Français', + selectText: 'Langues', + editLinkText: 'Editer cette page sur Github', + nav: [ + { + text: 'Guide', + link: '/fr/guide/' + }, + { + text: 'API', + link: '/fr/api/' + }, + { + text: 'v3.x', + items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org' }] + }, + { + text: 'Notes de version', + link: 'https://github.com/vuejs/vue-router/releases' + } + ], + sidebar: [ + '/fr/installation.md', + { + title: 'Essentiels', + collapsable: false, + children: [ + '/fr/guide/', + '/fr/guide/essentials/dynamic-matching.md', + '/fr/guide/essentials/nested-routes.md', + '/fr/guide/essentials/navigation.md', + '/fr/guide/essentials/named-routes.md', + '/fr/guide/essentials/named-views.md', + '/fr/guide/essentials/redirect-and-alias.md', + '/fr/guide/essentials/passing-props.md', + '/fr/guide/essentials/history-mode.md' + ] + }, + { + title: 'Avancés', + collapsable: false, + children: [ + '/fr/guide/advanced/navigation-guards.md', + '/fr/guide/advanced/meta.md', + '/fr/guide/advanced/transitions.md', + '/fr/guide/advanced/data-fetching.md', + '/fr/guide/advanced/scroll-behavior.md', + '/fr/guide/advanced/lazy-loading.md' + ] + } + ] + } } } -} +}) diff --git a/docs/.vuepress/public/icons/android-chrome-192x192.png b/docs/.vuepress/public/icons/android-chrome-192x192.png new file mode 100644 index 000000000..b02aa64d9 Binary files /dev/null and b/docs/.vuepress/public/icons/android-chrome-192x192.png differ diff --git a/docs/.vuepress/public/icons/android-chrome-512x512.png b/docs/.vuepress/public/icons/android-chrome-512x512.png new file mode 100644 index 000000000..06088b011 Binary files /dev/null and b/docs/.vuepress/public/icons/android-chrome-512x512.png differ diff --git a/docs/.vuepress/public/icons/apple-touch-icon-120x120.png b/docs/.vuepress/public/icons/apple-touch-icon-120x120.png new file mode 100644 index 000000000..1427cf627 Binary files /dev/null and b/docs/.vuepress/public/icons/apple-touch-icon-120x120.png differ diff --git a/docs/.vuepress/public/icons/apple-touch-icon-152x152.png b/docs/.vuepress/public/icons/apple-touch-icon-152x152.png new file mode 100644 index 000000000..f24d454a2 Binary files /dev/null and b/docs/.vuepress/public/icons/apple-touch-icon-152x152.png differ diff --git a/docs/.vuepress/public/icons/apple-touch-icon-180x180.png b/docs/.vuepress/public/icons/apple-touch-icon-180x180.png new file mode 100644 index 000000000..404e192a9 Binary files /dev/null and b/docs/.vuepress/public/icons/apple-touch-icon-180x180.png differ diff --git a/docs/.vuepress/public/icons/apple-touch-icon-60x60.png b/docs/.vuepress/public/icons/apple-touch-icon-60x60.png new file mode 100644 index 000000000..cf10a5602 Binary files /dev/null and b/docs/.vuepress/public/icons/apple-touch-icon-60x60.png differ diff --git a/docs/.vuepress/public/icons/apple-touch-icon-76x76.png b/docs/.vuepress/public/icons/apple-touch-icon-76x76.png new file mode 100644 index 000000000..c500769e3 Binary files /dev/null and b/docs/.vuepress/public/icons/apple-touch-icon-76x76.png differ diff --git a/docs/.vuepress/public/icons/apple-touch-icon.png b/docs/.vuepress/public/icons/apple-touch-icon.png new file mode 100644 index 000000000..03c0c5d5e Binary files /dev/null and b/docs/.vuepress/public/icons/apple-touch-icon.png differ diff --git a/docs/.vuepress/public/icons/favicon-16x16.png b/docs/.vuepress/public/icons/favicon-16x16.png new file mode 100644 index 000000000..42af00963 Binary files /dev/null and b/docs/.vuepress/public/icons/favicon-16x16.png differ diff --git a/docs/.vuepress/public/icons/favicon-32x32.png b/docs/.vuepress/public/icons/favicon-32x32.png new file mode 100644 index 000000000..46ca04dee Binary files /dev/null and b/docs/.vuepress/public/icons/favicon-32x32.png differ diff --git a/docs/.vuepress/public/icons/msapplication-icon-144x144.png b/docs/.vuepress/public/icons/msapplication-icon-144x144.png new file mode 100644 index 000000000..7808237a1 Binary files /dev/null and b/docs/.vuepress/public/icons/msapplication-icon-144x144.png differ diff --git a/docs/.vuepress/public/icons/mstile-150x150.png b/docs/.vuepress/public/icons/mstile-150x150.png new file mode 100644 index 000000000..3b37a43ae Binary files /dev/null and b/docs/.vuepress/public/icons/mstile-150x150.png differ diff --git a/docs/.vuepress/public/icons/safari-pinned-tab.svg b/docs/.vuepress/public/icons/safari-pinned-tab.svg new file mode 100644 index 000000000..732afd8eb --- /dev/null +++ b/docs/.vuepress/public/icons/safari-pinned-tab.svg @@ -0,0 +1,149 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/docs/.vuepress/public/images/vueschool/vs-close.svg b/docs/.vuepress/public/images/vueschool/vs-close.svg new file mode 100644 index 000000000..0e2f31fcd --- /dev/null +++ b/docs/.vuepress/public/images/vueschool/vs-close.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/docs/.vuepress/public/images/vueschool/vs-fw-bg-small.svg b/docs/.vuepress/public/images/vueschool/vs-fw-bg-small.svg new file mode 100644 index 000000000..a914f4005 --- /dev/null +++ b/docs/.vuepress/public/images/vueschool/vs-fw-bg-small.svg @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/.vuepress/public/images/vueschool/vs-fw-bg.svg b/docs/.vuepress/public/images/vueschool/vs-fw-bg.svg new file mode 100644 index 000000000..8c5222062 --- /dev/null +++ b/docs/.vuepress/public/images/vueschool/vs-fw-bg.svg @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/.vuepress/public/images/vueschool/vs-iso.svg b/docs/.vuepress/public/images/vueschool/vs-iso.svg new file mode 100644 index 000000000..a95d92607 --- /dev/null +++ b/docs/.vuepress/public/images/vueschool/vs-iso.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/docs/.vuepress/public/images/vueschool/vs-logo.svg b/docs/.vuepress/public/images/vueschool/vs-logo.svg new file mode 100644 index 000000000..b44c00458 --- /dev/null +++ b/docs/.vuepress/public/images/vueschool/vs-logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/docs/.vuepress/public/logo.png b/docs/.vuepress/public/logo.png new file mode 100644 index 000000000..60e17006a Binary files /dev/null and b/docs/.vuepress/public/logo.png differ diff --git a/docs/.vuepress/public/sponsors/fincliplogo_black_svg.svg b/docs/.vuepress/public/sponsors/fincliplogo_black_svg.svg new file mode 100644 index 000000000..848f93d56 --- /dev/null +++ b/docs/.vuepress/public/sponsors/fincliplogo_black_svg.svg @@ -0,0 +1 @@ +五行代码,让你的APP拥有小程序运行能力 \ No newline at end of file diff --git a/docs/.vuepress/public/sponsors/fincliplogo_white_svg.svg b/docs/.vuepress/public/sponsors/fincliplogo_white_svg.svg new file mode 100644 index 000000000..3254e5384 --- /dev/null +++ b/docs/.vuepress/public/sponsors/fincliplogo_white_svg.svg @@ -0,0 +1 @@ +五行代码,让你的APP拥有小程序运行能力 \ No newline at end of file diff --git a/docs/.vuepress/public/sponsors/passionate-people-dark.png b/docs/.vuepress/public/sponsors/passionate-people-dark.png new file mode 100644 index 000000000..028baf65b Binary files /dev/null and b/docs/.vuepress/public/sponsors/passionate-people-dark.png differ diff --git a/docs/.vuepress/public/sponsors/passionate-people-light.png b/docs/.vuepress/public/sponsors/passionate-people-light.png new file mode 100644 index 000000000..61ac71af2 Binary files /dev/null and b/docs/.vuepress/public/sponsors/passionate-people-light.png differ diff --git a/docs/.vuepress/public/sponsors/vuejobs.png b/docs/.vuepress/public/sponsors/vuejobs.png new file mode 100644 index 000000000..50b7b7474 Binary files /dev/null and b/docs/.vuepress/public/sponsors/vuejobs.png differ diff --git a/docs/.vuepress/public/sponsors/vuetify-logo-dark-text.svg b/docs/.vuepress/public/sponsors/vuetify-logo-dark-text.svg new file mode 100644 index 000000000..6f4ff0708 --- /dev/null +++ b/docs/.vuepress/public/sponsors/vuetify-logo-dark-text.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/docs/.vuepress/public/sponsors/vuetify-logo-light-text.svg b/docs/.vuepress/public/sponsors/vuetify-logo-light-text.svg new file mode 100644 index 000000000..33f442df8 --- /dev/null +++ b/docs/.vuepress/public/sponsors/vuetify-logo-light-text.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/docs/.vuepress/style.styl b/docs/.vuepress/style.styl deleted file mode 100644 index de6fb8800..000000000 --- a/docs/.vuepress/style.styl +++ /dev/null @@ -1,14 +0,0 @@ -.bit-sponsor - font-weight 600 - background-color #f3f6f8 - padding 0.6em 1.2em - border-radius 8px - display inline-block - margin 1em 0 !important - a - color #999 - img - height 40px - margin-left 15px - img, span - vertical-align middle diff --git a/docs/.vuepress/styles/index.styl b/docs/.vuepress/styles/index.styl new file mode 100644 index 000000000..a8f9a8a68 --- /dev/null +++ b/docs/.vuepress/styles/index.styl @@ -0,0 +1,54 @@ +.bit-sponsor + font-weight 600 + background-color #f3f6f8 + padding 0.6em 1.2em + border-radius 8px + display inline-block + margin 1em 0 !important + a + color #999 + img + height 40px + margin-left 15px + img, span + vertical-align middle + + +.vueschool + background-color #e7ecf3 + padding 1em 1.25em + border-radius 2px + color #486491 + position relative + display flex + a + color #486491 !important + position relative + padding-left 36px + &:before + content '' + position absolute + display block + width 30px + height 30px + top calc(50% - 15px); + left -4px + border-radius 50% + background-color #73abfe + &:after + content '' + position absolute + display block + width 0 + height 0 + top calc(50% - 5px) + left 8px + border-top 5px solid transparent + border-bottom 5px solid transparent + border-left 8px solid #fff + +@media (max-width: 719px) { + .vueschool { + display: inline-flex; + } +} diff --git a/docs/.vuepress/theme/Layout.vue b/docs/.vuepress/theme/Layout.vue new file mode 100644 index 000000000..a27d64a62 --- /dev/null +++ b/docs/.vuepress/theme/Layout.vue @@ -0,0 +1,160 @@ + + + + + + + diff --git a/docs/.vuepress/theme/components/BuySellAds.vue b/docs/.vuepress/theme/components/BuySellAds.vue new file mode 100644 index 000000000..17df4bd16 --- /dev/null +++ b/docs/.vuepress/theme/components/BuySellAds.vue @@ -0,0 +1,115 @@ + + + + + diff --git a/docs/.vuepress/theme/components/CarbonAds.vue b/docs/.vuepress/theme/components/CarbonAds.vue new file mode 100644 index 000000000..8864e44b1 --- /dev/null +++ b/docs/.vuepress/theme/components/CarbonAds.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/docs/.vuepress/theme/components/VueSchool/BannerTop.vue b/docs/.vuepress/theme/components/VueSchool/BannerTop.vue new file mode 100644 index 000000000..02a3b756a --- /dev/null +++ b/docs/.vuepress/theme/components/VueSchool/BannerTop.vue @@ -0,0 +1,244 @@ + + + diff --git a/docs/.vuepress/theme/index.js b/docs/.vuepress/theme/index.js new file mode 100644 index 000000000..b91b8a576 --- /dev/null +++ b/docs/.vuepress/theme/index.js @@ -0,0 +1,3 @@ +module.exports = { + extend: '@vuepress/theme-default' +} diff --git a/docs/README.md b/docs/README.md index e6bb82409..69f6215fb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,10 +1,10 @@ -# Introduction - - - -:::tip VERSION NOTE -For TypeScript users, `vue-router@3.0+` requires `vue@2.5+`, and vice versa. -::: +--- +home: true +heroImage: /logo.png +actionText: Get Started → +actionLink: /installation.html +footer: MIT Licensed | Copyright © 2014-present Evan You, Eduardo San Martin Morote +--- Vue Router is the official router for [Vue.js](http://vuejs.org). It deeply integrates with Vue.js core to make building Single Page Applications with Vue.js a breeze. Features include: @@ -18,3 +18,5 @@ Vue Router is the official router for [Vue.js](http://vuejs.org). It deeply inte - Customizable Scroll Behavior [Get started](./guide/) or play with the [examples](https://github.com/vuejs/vue-router/tree/dev/examples) (see [`README.md`](https://github.com/vuejs/vue-router/) to run them). + + diff --git a/docs/api/README.md b/docs/api/README.md index 5d56d8352..5c9dacc60 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -4,8 +4,6 @@ sidebar: auto # API Reference - - ## `` `` is the component for enabling user navigation in a router-enabled app. The target location is specified with the `to` prop. It renders as an `` tag with correct `href` by default, but can be configured with the `tag` prop. In addition, the link automatically gets an active CSS class when the target route is active. @@ -13,22 +11,54 @@ sidebar: auto `` is preferred over hard-coded `` for the following reasons: - It works the same way in both HTML5 history mode and hash mode, so if you ever decide to switch mode, or when the router falls back to hash mode in IE9, nothing needs to be changed. - - In HTML5 history mode, `router-link` will intercept the click event so that the browser doesn't try to reload the page. - - When you are using the `base` option in HTML5 history mode, you don't need to include it in `to` prop's URLs. -### Applying Active Class to Outer Element +### `v-slot` API (3.1.0+) -Sometimes we may want the active class to be applied to an outer element rather than the `` tag itself, in that case, you can render that outer element using `` and wrap the raw `` tag inside: +`router-link` exposes a low level customization through a [scoped slot](https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots). This is a more advanced API that primarily targets library authors but can come in handy for developers as well, most of the time in a custom component like a _NavLink_ or other. -``` html - - /foo +**When using the `v-slot` API, it is required to pass one single child to `router-link`**. If you don't, `router-link` will wrap its children in a `span` element. + +```html + + {{ route.fullPath }} ``` -In this case the `` will be the actual link (and will get the correct `href`), but the active class will be applied to the outer `
  • `. +- `href`: resolved url. This would be the `href` attribute of an `a` element +- `route`: resolved normalized location +- `navigate`: function to trigger the navigation. **It will automatically prevent events when necessary**, the same way `router-link` does +- `isActive`: `true` if the [active class](#active-class) should be applied. Allows to apply an arbitrary class +- `isExactActive`: `true` if the [exact active class](#exact-active-class) should be applied. Allows to apply an arbitrary class + +#### Example: Applying Active Class to Outer Element + +Sometimes we may want the active class to be applied to an outer element rather than the `` tag itself, in that case, you can wrap that element inside a `router-link` and use the `v-slot` properties to create your link: + +```html + +
  • + {{ route.fullPath }} +
  • +
    +``` + +:::tip +If you add a `target="_blank"` to your `a` element, you must omit the `@click="navigate"` handler. +::: ## `` Props @@ -39,7 +69,7 @@ In this case the `` will be the actual link (and will get the correct `href`) Denotes the target route of the link. When clicked, the value of the `to` prop will be passed to `router.push()` internally, so the value can be either a string or a location descriptor object. - ``` html + ```html Home @@ -58,7 +88,9 @@ In this case the `` will be the actual link (and will get the correct `href`) User - Register + Register ``` ### replace @@ -68,7 +100,7 @@ In this case the `` will be the actual link (and will get the correct `href`) Setting `replace` prop will call `router.replace()` instead of `router.push()` when clicked, so the navigation will not leave a history record. - ``` html + ```html ``` @@ -79,7 +111,7 @@ In this case the `` will be the actual link (and will get the correct `href`) Setting `append` prop always appends the relative path to the current path. For example, assuming we are navigating from `/a` to a relative link `b`, without `append` we will end up at `/b`, but with `append` we will end up at `/a/b`. - ``` html + ```html ``` @@ -90,7 +122,7 @@ In this case the `` will be the actual link (and will get the correct `href`) Sometimes we want `` to render as another tag, e.g `
  • `. Then we can use `tag` prop to specify which tag to render to, and it will still listen to click events for navigation. - ``` html + ```html foo
  • foo
  • @@ -112,13 +144,34 @@ In this case the `
    ` will be the actual link (and will get the correct `href`) One consequence of this is that `` will be active for every route! To force the link into "exact match mode", use the `exact` prop: - ``` html + ```html - + ``` Check out more examples explaining active link class [live](https://jsfiddle.net/8xrk1n9f/). +### exact-path + +> New in 3.5.0 + +- type: `boolean` +- default: `false` + + Allows matching only using the `path` section of the url, effectively ignoring the `query` and the `hash` sections. + + ```html + + + ``` + +### exact-path-active-class + +- type: `string` +- default: `"router-link-exact-path-active"` + + Configure the active CSS class applied when the link is active with exact path match. Note the default value can also be configured globally via the `linkExactPathActiveClass` router constructor option. + ### event - type: `string | Array` @@ -133,15 +186,22 @@ In this case the `` will be the actual link (and will get the correct `href`) Configure the active CSS class applied when the link is active with exact match. Note the default value can also be configured globally via the `linkExactActiveClass` router constructor option. +### aria-current-value + +- type: `'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'` +- default: `"page"` + + Configure the value of `aria-current` when the link is active with exact match. It must be one of the [allowed values for aria-current](https://www.w3.org/TR/wai-aria-1.2/#aria-current) in the ARIA spec. In most cases, the default of `page` should be the best fit. + ## `` -The `` component is a functional component that renders the matched component for the given path. Components rendered in `` can also contain its own ``, which will render components for nested paths. +The `` component is a functional component that renders the matched component for the given path. Components rendered in `` can also contain their own ``, which will render components for nested paths. Any non-name props will be passed along to the rendered component, however most of the time the per-route data is contained in the route's params. -Since it's just a component, it works with `` and ``. When using the both together, make sure to use `` inside: +Since it's just a component, it works with `` and ``. When using them both together, make sure to use `` inside: -``` html +```html @@ -166,22 +226,22 @@ Since it's just a component, it works with `` and ``. Wh Type declaration for `RouteConfig`: - ``` js - declare type RouteConfig = { - path: string; - component?: Component; - name?: string; // for named routes - components?: { [name: string]: Component }; // for named views - redirect?: string | Location | Function; - props?: boolean | Object | Function; - alias?: string | Array; - children?: Array; // for nested routes - beforeEnter?: (to: Route, from: Route, next: Function) => void; - meta?: any; + ```ts + interface RouteConfig = { + path: string, + component?: Component, + name?: string, // for named routes + components?: { [name: string]: Component }, // for named views + redirect?: string | Location | Function, + props?: boolean | Object | Function, + alias?: string | Array, + children?: Array, // for nested routes + beforeEnter?: (to: Route, from: Route, next: Function) => void, + meta?: any, // 2.6.0+ - caseSensitive?: boolean; // use case sensitive match? (default: false) - pathToRegexpOptions?: Object; // path-to-regexp options for compiling regex + caseSensitive?: boolean, // use case sensitive match? (default: false) + pathToRegexpOptions?: Object // path-to-regexp options for compiling regex } ``` @@ -231,11 +291,11 @@ Since it's just a component, it works with `` and ``. Wh Signature: - ``` + ```ts type PositionDescriptor = { x: number, y: number } | { selector: string } | - ?{} + void type scrollBehaviorHandler = ( to: Route, @@ -282,15 +342,37 @@ Since it's just a component, it works with `` and ``. Wh The current route represented as a [Route Object](#the-route-object). +### router.START_LOCATION (3.5.0+) + +- type: `Route` + + Initial route location represented as a [Route Object](#the-route-object) where the router starts at. Can be used in navigation guards to differentiate the initial navigation. + + ```js + import VueRouter from 'vue-router' + + const router = new VueRouter({ + // ... + }) + + router.beforeEach((to, from) => { + if (from === VueRouter.START_LOCATION) { + // initial navigation + } + }) + ``` + ## Router Instance Methods ### router.beforeEach + ### router.beforeResolve + ### router.afterEach Signatures: -``` js +```js router.beforeEach((to, from, next) => { /* must call `next` */ }) @@ -307,16 +389,22 @@ Add global navigation guards. See [Navigation Guards](../guide/advanced/navigati All three methods return a function that removes the registered guard/hook. ### router.push + ### router.replace + ### router.go + ### router.back + ### router.forward Signatures: -``` js +```js router.push(location, onComplete?, onAbort?) +router.push(location).then(onComplete).catch(onAbort) router.replace(location, onComplete?, onAbort?) +router.replace(location).then(onComplete).catch(onAbort) router.go(n) router.back() router.forward() @@ -324,11 +412,13 @@ router.forward() Programmatically navigate to a new URL. See [Programmatic Navigation](../guide/essentials/navigation.md) for more details. +These functions can only be called after installing the Router plugin and passing it to the root Vue instance as shown in the [Getting Started](../guide/README.md). + ### router.getMatchedComponents Signature: -``` js +```js const matchedComponents: Array = router.getMatchedComponents(location?) ``` @@ -338,7 +428,7 @@ Returns an Array of the components (definition/constructor, not instances) match Signature: -``` js +```js const resolved: { location: Location; route: Route; @@ -353,19 +443,57 @@ Reverse URL resolving. Given location in form same as used in ``. ### router.addRoutes +_DEPRECATED_: use [`router.addRoute()`](#router-addroute) instead. + Signature: -``` js +```ts router.addRoutes(routes: Array) ``` Dynamically add more routes to the router. The argument must be an Array using the same route config format with the `routes` constructor option. +### router.addRoute + +> New in 3.5.0 + +Add a new route to the router. If the route has a `name` and there is already an existing one with the same one, it overwrites it. + +Signature: + +```ts +addRoute(route: RouteConfig): () => void +``` + +### router.addRoute + +> New in 3.5.0 + +Add a new route record as the child of an existing route. If the route has a `name` and there is already an existing one with the same one, it overwrites it. + +Signature: + +```ts +addRoute(parentName: string, route: RouteConfig): () => void +``` + +### router.getRoutes + +> New in 3.5.0 + +Get the list of all the active route records. **Note only documented properties are considered Public API**, avoid using any other property e.g. `regex` as it doesn't exist on Vue Router 4. + +Signature: + +```ts +getRoutes(): RouteRecord[] +``` + ### router.onReady Signature: -``` js +```js router.onReady(callback, [errorCallback]) ``` @@ -379,7 +507,7 @@ The second argument `errorCallback` is only supported in 2.4+. It will be called Signature: -``` js +```js router.onError(callback) ``` @@ -407,7 +535,7 @@ The route object can be found in multiple places: - Inside navigation guards as the first two arguments: - ``` js + ```js router.beforeEach((to, from, next) => { // `to` and `from` are both route objects }) @@ -415,9 +543,9 @@ The route object can be found in multiple places: - Inside the `scrollBehavior` function as the first two arguments: - ``` js + ```js const router = new VueRouter({ - scrollBehavior (to, from, savedPosition) { + scrollBehavior(to, from, savedPosition) { // `to` and `from` are both route objects } }) @@ -425,47 +553,55 @@ The route object can be found in multiple places: ### Route Object Properties -- **$route.path** +- **\$route.path** - type: `string` A string that equals the path of the current route, always resolved as an absolute path. e.g. `"/foo/bar"`. -- **$route.params** +- **\$route.params** - type: `Object` An object that contains key/value pairs of dynamic segments and star segments. If there are no params the value will be an empty object. -- **$route.query** +- **\$route.query** - type: `Object` An object that contains key/value pairs of the query string. For example, for a path `/foo?user=1`, we get `$route.query.user == 1`. If there is no query the value will be an empty object. -- **$route.hash** +- **\$route.meta** + + - type: `Object` + + An object that contains key/value pairs of the route meta object. If there are no meta properties the value will be an empty object. + +- **\$route.hash** - type: `string` The hash of the current route (with the `#`), if it has one. If no hash is present the value will be an empty string. -- **$route.fullPath** +- **\$route.fullPath** - type: `string` The full resolved URL including query and hash. -- **$route.matched** +- **\$route.matched** - type: `Array` An Array containing **route records** for all nested path segments of the current route. Route records are the copies of the objects in the `routes` configuration Array (and in `children` Arrays): - ``` js + ```js const router = new VueRouter({ routes: [ // the following object is a route record - { path: '/foo', component: Foo, + { + path: '/foo', + component: Foo, children: [ // this is also a route record { path: 'bar', component: Bar } @@ -477,11 +613,11 @@ The route object can be found in multiple places: When the URL is `/foo/bar`, `$route.matched` will be an Array containing both objects (cloned), in parent to child order. -- **$route.name** +- **\$route.name** The name of the current route, if it has one. (See [Named Routes](../guide/essentials/named-routes.md)) -- **$route.redirectedFrom** +- **\$route.redirectedFrom** The name of the route being redirected from, if there were one. (See [Redirect and Alias](../guide/essentials/redirect-and-alias.md)) @@ -491,11 +627,11 @@ The route object can be found in multiple places: These properties are injected into every child component by passing the router instance to the root instance as the `router` option. -- **this.$router** +- **this.\$router** The router instance. -- **this.$route** +- **this.\$route** The current active [Route](#the-route-object). This property is read-only and its properties are immutable, but it can be watched. diff --git a/docs/fr/README.md b/docs/fr/README.md index 3172f6a2e..b46196db2 100644 --- a/docs/fr/README.md +++ b/docs/fr/README.md @@ -1,10 +1,10 @@ -# Introduction - - - -:::tip VERSION NOTE -Pour les utilisateurs de TypeScript, `vue-router@3.0+` requière `vue@2.5+`, et vice versa. -::: +--- +home: true +heroImage: /logo.png +actionText: Get Started → +actionLink: /fr/installation.html +footer: MIT Licensed | Copyright © 2014-present Evan You, Eduardo San Martin Morote +--- Vue Router est le router officiel pour [Vue.js](http://vuejs.org). Il s'intègre aisément avec Vue.js pour faire des applications mono page avec Vue.js. Fonctionnalités incluses: @@ -18,3 +18,5 @@ Vue Router est le router officiel pour [Vue.js](http://vuejs.org). Il s'intègre - Gestion du scroll [Pour commencer](./guide/) ou jouer avec les [exemples](https://github.com/vuejs/vue-router/tree/dev/examples) (voir [`README.md`](https://github.com/vuejs/vue-router/) pour les faire fonctionner). + + diff --git a/docs/fr/api/README.md b/docs/fr/api/README.md index 42af63eed..0006b0dbc 100644 --- a/docs/fr/api/README.md +++ b/docs/fr/api/README.md @@ -4,8 +4,6 @@ sidebar: auto # API - - ## `` `` est le composant pour activer la navigation utilisateur dans une application où le routeur est activé. La localisation cible est spécifiée grâce à la prop `to`. Il est rendu en tant que balise `` avec le `href` correct par défaut, mais peut être configuré grâce à la prop `tag`. De plus, le lien se verra attribuer une classe CSS active lorsque la route cible est active. @@ -16,7 +14,31 @@ sidebar: auto - Dans le mode historique HTML5, `router-link` interceptera l'évènement du clic, comme ça le navigateur n'essaiera pas de rafraichir la page. -- En utilisant l'option `base` dans le mode historique HTML5, vous n'avez pas besoin +- En utilisant l'option `base` dans le mode historique HTML5, vous n'avez pas besoin de l'inclure dans la prop `to` + +### `v-slot` API (3.1.0+) + +`router-link` est fortement personnalisable via une [slot avec portée](https://fr.vuejs.org/v2/guide/components-slots.html#Slots-avec-portee). C'est une API qui cible principalement les créateurs de bibliothèque, mais elle peut aussi servir pour les développeurs, le plus souvent dans des composants personnalisés tel qu'un _NavLink_ et autre. + +**Lors de l'utilisation `v-slot` API, il faut obligatoirement passer un composant enfant unique au `router-link`**. Si vous ne le faites pas, `router-link` va entourer ses enfants avec une balise `span`. + +```html + + {{ route.fullPath }} + +``` + +- `href`: URL résolue. Ce serait l'attribut `href` d'une balise `a` +- `route`: localisation normalisée et résolue +- `navigate`: fonction pour lancer la navigation. **En cas de nécessité il va automatiquement empêcher les événements**, de la même façon que `router-link` +- `isActive`: `true` si [active class](#active-class) devrait être appliqué. Permet d'appliquer une classe arbitraire +- `isExactActive`: `true` si [exact active class](#exact-active-class) devrait être appliqué. Permet d'appliquer une classe arbitraire ### Appliquer la classe active à l'élément extérieur @@ -55,10 +77,14 @@ Dans ce cas, `` sera le lien actuel (et récupèrera le bon `href`), mais la Accueil - Utilisateur + Utilisateur - S'enregistrer + S'enregistrer ``` ### replace @@ -169,7 +195,7 @@ Le composant `` est un composant fonctionnel qui fait le rendu du c // 2.6.0+ caseSensitive?: boolean, // use case sensitive match? (default: false) - pathToRegexpOptions?: Object, // path-to-regexp options for compiling regex + pathToRegexpOptions?: Object // path-to-regexp options for compiling regex } ``` @@ -219,11 +245,11 @@ Le composant `` est un composant fonctionnel qui fait le rendu du c Signature : - ``` + ```ts type PositionDescriptor = { x: number, y: number } | { selector: string } | - ?{} + void type scrollBehaviorHandler = ( to: Route, @@ -361,7 +387,7 @@ L'objet `Route` peut être trouvé à plusieurs endroits : const router = new VueRouter({ scrollBehavior(to, from, savedPosition) { // `to` et `from` sont tous les deux des objets Route - }, + } }) ``` @@ -412,10 +438,10 @@ L'objet `Route` peut être trouvé à plusieurs endroits : component: Foo, children: [ // c'est aussi un itinéraire - { path: 'bar', component: Bar }, - ], - }, - ], + { path: 'bar', component: Bar } + ] + } + ] }) ``` diff --git a/docs/fr/guide/README.md b/docs/fr/guide/README.md index 0047b8993..c58572205 100644 --- a/docs/fr/guide/README.md +++ b/docs/fr/guide/README.md @@ -1,19 +1,17 @@ # Pour commencer - - ::: tip Note Nous utiliserons [ES2015](https://github.com/lukehoban/es6features) dans les exemples de code dans ce guide. - Tous les exemples utiliseront la version complète de Vue pour rendre l'analyse de template possible. Plus de détails [ici](https://fr.vuejs.org/guide/installation.html#Runtime-Compiler-vs-Runtime-seul). +Tous les exemples utiliseront la version complète de Vue pour rendre l'analyse de template possible. Plus de détails [ici](https://fr.vuejs.org/guide/installation.html#Runtime-Compiler-vs-Runtime-seul). ::: Créer une application monopage avec Vue + Vue Router est vraiment simple. Avec Vue.js, nous concevons déjà notre application avec des composants. En ajoutant vue-router dans notre application, tout ce qu'il nous reste à faire est de relier nos composants aux routes, et de laisser vue-router faire le rendu. Voici un exemple de base : ## HTML -``` html - - +```html + +

    Bonjour l'application !

    @@ -32,7 +30,7 @@ Créer une application monopage avec Vue + Vue Router est vraiment simple. Avec ## JavaScript -``` js +```js // 0. Si vous utilisez un système de module (par ex. via vue-cli), il faut importer Vue et Vue Router et ensuite appeler `Vue.use(VueRouter)`. // 1. Définissez les composants de route. @@ -73,16 +71,14 @@ En injectant le routeur, nous y avons accès à travers `this.$router`. Nous avo // Home.vue export default { computed: { - username () { + username() { // Nous verrons ce que représente `params` dans un instant. return this.$route.params.username } }, methods: { - goBack () { - window.history.length > 1 - ? this.$router.go(-1) - : this.$router.push('/') + goBack() { + window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/') } } } diff --git a/docs/fr/guide/advanced/lazy-loading.md b/docs/fr/guide/advanced/lazy-loading.md index 9324281fa..ae138cf72 100644 --- a/docs/fr/guide/advanced/lazy-loading.md +++ b/docs/fr/guide/advanced/lazy-loading.md @@ -6,13 +6,16 @@ En combinant la [fonctionnalité de composant asynchrone](https://fr.vuejs.org/v Premièrement, un composant asynchrone peut définir une fonction fabrique qui retourne une Promesse (qui devrait résoudre le composant lui-même) : -``` js -const Foo = () => Promise.resolve({ /* définition du composant */ }) +```js +const Foo = () => + Promise.resolve({ + /* définition du composant */ + }) ``` Deuxièmement, avec webpack 2, nous pouvons utiliser la syntaxe d'[import dynamique](https://github.com/tc39/proposal-dynamic-import) pour indiquer un point de scission de code : -``` js +```js import('./Foo.vue') // returns a Promise ``` @@ -22,25 +25,23 @@ si vous utilisez Babel, vous aurez besoin d'ajouter le plugin [syntax-dynamic-im En combinant les deux, on définit un composant asynchrone qui sera automatiquement scindé par webpack : -``` js +```js const Foo = () => import('./Foo.vue') ``` Rien n'a besoin d'être modifié dans la configuration de la route, utilisez `Foo` comme d'habitude. -``` js +```js const router = new VueRouter({ - routes: [ - { path: '/foo', component: Foo } - ] + routes: [{ path: '/foo', component: Foo }] }) ``` ## Grouper des composants dans le même fragment -Parfois on aimerait grouper tous les composants imbriqués sous la même route, dans un seul et même fragment asynchrone. Pour arriver à cela, nous avons besoin d'utiliser les [fragments nommés](https://webpack.js.org/guides/code-splitting-async/#chunk-names) en donnant un nom au fragment en utilisant une syntaxe de commentaire spéciale (requires webpack > 2.4) : +Parfois on aimerait grouper tous les composants imbriqués sous la même route, dans un seul et même fragment asynchrone. Pour arriver à cela, nous avons besoin d'utiliser les [fragments nommés](https://webpack.js.org/api/module-methods/#magic-comments) en donnant un nom au fragment en utilisant une syntaxe de commentaire spéciale (requires webpack > 2.4) : -``` js +```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') diff --git a/docs/fr/guide/advanced/navigation-guards.md b/docs/fr/guide/advanced/navigation-guards.md index 9bcb01cb9..4ee3d4fad 100644 --- a/docs/fr/guide/advanced/navigation-guards.md +++ b/docs/fr/guide/advanced/navigation-guards.md @@ -102,7 +102,7 @@ const Foo = { } ``` -L'interception `beforeRouteEnter` **n'**a **PAS** accès à `this`, car l'interception est appelée avant que la navigation soit confirmée, et le nouveau composant entrant n'a même pas encore été créé. +L'interception `beforeRouteEnter` **n'a PAS** accès à `this`, car l'interception est appelée avant que la navigation soit confirmée, et le nouveau composant entrant n'a même pas encore été créé. Cependant, vous pouvez accéder à l'instance en passant dans la fonction de rappel `next`. Cette fonction de rappel va être appelée quand la navigation sera confirmée, et l'instance du composant sera passée à la fonction de rappel en tant qu'argument : diff --git a/docs/fr/guide/essentials/dynamic-matching.md b/docs/fr/guide/essentials/dynamic-matching.md index bfee2918f..76d1fbf5a 100644 --- a/docs/fr/guide/essentials/dynamic-matching.md +++ b/docs/fr/guide/essentials/dynamic-matching.md @@ -29,9 +29,9 @@ Vous pouvez regarder un exemple en ligne [ici](https://jsfiddle.net/yyx990803/4x Vous pouvez avoir plusieurs segments dynamiques pour une même route, et ils seront associés aux champs associés dans `$route.params`. Des exemples : -| motif | chemin concordant | $route.params | -|---------|------|--------| -| /utilisateur/:username | /utilisateur/evan | `{ username: 'evan' }` | +| motif | chemin concordant | $route.params | +| -------------------------------------- | ---------------------------- | ------------------------------------ | +| /utilisateur/:username | /utilisateur/evan | `{ username: 'evan' }` | | /utilisateur/:username/billet/:post_id | /utilisateur/evan/billet/123 | `{ username: 'evan', post_id: 123 }` | En plus de `$route.params`, l'objet `$route` expose également d'autres informations utiles comme la `$route.query` (s'il y a une requête dans l'URL), `$route.hash`, etc. Vous pouvez accéder à tous les détails de cela dans la [référence de l'API](../../api/#the-route-object). @@ -67,7 +67,7 @@ const User = { ## Motifs de concordance avancés -`vue-router` utilise [path-to-regexp](https://github.com/pillarjs/path-to-regexp) comme moteur de concordance de chemin, il supporte donc plusieurs motifs de concordance avancés tels que la présence optionnelle de segments dynamiques, aucun ou plusieurs motifs, plus d'options par motifs, et même des motifs d'expressions régulières personnalisés. Consultez cette [documentation](https://github.com/pillarjs/path-to-regexp#parameters) pour utiliser ces motifs avancés et [cet exemple](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) pour les utiliser avec `vue-router`. +`vue-router` utilise [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) comme moteur de concordance de chemin, il supporte donc plusieurs motifs de concordance avancés tels que la présence optionnelle de segments dynamiques, aucun ou plusieurs motifs, plus d'options par motifs, et même des motifs d'expressions régulières personnalisés. Consultez cette [documentation](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters) pour utiliser ces motifs avancés et [cet exemple](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) pour les utiliser avec `vue-router`. ## Priorité de concordance diff --git a/docs/fr/guide/essentials/history-mode.md b/docs/fr/guide/essentials/history-mode.md index 2cd21c043..8337db43a 100644 --- a/docs/fr/guide/essentials/history-mode.md +++ b/docs/fr/guide/essentials/history-mode.md @@ -4,7 +4,7 @@ Le mode par défaut de `vue-router` est le _mode hash_. Il utilise la partie has Pour nous passer du hash, nous pouvons utiliser le **mode historique** qui utilisera l'API `history.pushState` afin de permettre une navigation sans rechargement de page : -``` js +```js const router = new VueRouter({ mode: 'history', routes: [...] @@ -22,6 +22,9 @@ Ne vous inquiétez pas. Pour résoudre ce problème, il vous suffit d'ajouter un ### Apache ```apache + + Options -MultiViews + RewriteEngine On RewriteBase / @@ -32,7 +35,7 @@ Ne vous inquiétez pas. Pour résoudre ce problème, il vous suffit d'ajouter un ``` -Instead of `mod_rewrite`, you could also use [`FallbackResource`](https://httpd.apache.org/docs/2.2/mod/mod_dir.html#fallbackresource). +Au lieu de `mod_rewrite`, vous pouvez également utiliser [`FallbackResource`](https://httpd.apache.org/docs/2.2/mod/mod_dir.html#fallbackresource). ### nginx @@ -49,21 +52,23 @@ 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(`Impossible d'ouvrir le fichier "index.htm"`) - } +http + .createServer((req, res) => { + fs.readFile('index.html', 'utf-8', (err, content) => { + if (err) { + console.log(`Impossible d'ouvrir le fichier "index.html"`) + } - res.writeHead(200, { - 'Content-Type': 'text/html; charset=utf-8' - }) + res.writeHead(200, { + 'Content-Type': 'text/html; charset=utf-8' + }) - res.end(content) + res.end(content) + }) + }) + .listen(httpPort, () => { + console.log('Le serveur écoute à : http://localhost:%s', httpPort) }) -}).listen(httpPort, () => { - console.log('Le serveur écoute à : http://localhost:%s', httpPort) -}) ``` ### Node.js avec Express @@ -126,12 +131,10 @@ Ajouter ceci à votre fichier `firebase.json` : Il y a une limitation a tout ceci. Votre serveur ne renverra plus les erreurs 404 des chemins qui ne sont pas trouvés puisqu'il va servir à présent le fichier `index.html`. Pour contourner ce problème, vous pouvez implémenter une route concordant avec toutes les adresses en 404 dans votre application Vue : -``` js +```js const router = new VueRouter({ mode: 'history', - routes: [ - { path: '*', component: NotFoundComponent } - ] + routes: [{ path: '*', component: NotFoundComponent }] }) ``` diff --git a/docs/fr/guide/essentials/navigation.md b/docs/fr/guide/essentials/navigation.md index 76367579c..dbb747621 100644 --- a/docs/fr/guide/essentials/navigation.md +++ b/docs/fr/guide/essentials/navigation.md @@ -14,8 +14,8 @@ Pour naviguer vers un URL différent, utilisez `router.push`. Cette méthode ajo Cette méthode est appelée en interne quand vous cliquez sur ``, donc cliquer sur `` est équivalent à appeler `router.push(...)`. -| Déclarative | Programmatique | -|-------------|--------------| +| Déclarative | Programmatique | +| ------------------------- | ------------------ | | `` | `router.push(...)` | L'argument peut être une chaine de caractère représentant un chemin, ou un objet de description de destination. Des exemples : @@ -54,8 +54,8 @@ Dans la version 2.2.0+, vous pouvez optionnellement fournir les fonctions de rap Il agit comme `router.push`. La seule différence est que la navigation se fait sans ajouter de nouvelle entrée dans la pile de l'historique. Comme son nom l'indique, il remplace l'entrée courante. -| Déclarative | Programmatique | -|-------------|--------------| +| Déclarative | Programmatique | +| --------------------------------- | --------------------- | | `` | `router.replace(...)` | diff --git a/docs/fr/guide/essentials/nested-routes.md b/docs/fr/guide/essentials/nested-routes.md index be0fc9cfb..fa513fb64 100644 --- a/docs/fr/guide/essentials/nested-routes.md +++ b/docs/fr/guide/essentials/nested-routes.md @@ -58,13 +58,13 @@ const router = new VueRouter({ { // `UserProfile` va être rendu à l'intérieur du `` de `User` // quand `/utilisateur/:id/profil` concorde - path: 'profile', + path: 'profil', component: UserProfile }, { // `UserPosts` va être rendu à l'intérieur du `` de `User` // quand `/utilisateur/:id/billets` concorde - path: 'posts', + path: 'billets', component: UserPosts } ] @@ -85,7 +85,7 @@ const router = new VueRouter({ { path: '/utilisateur/:id', component: User, children: [ - // `UserProfile` va être rendu à l'intérieur du `` de `User` + // `UserHome` va être rendu à l'intérieur du `` de `User` // quand `/utilisateur/:id` concorde { path: '', component: UserHome }, diff --git a/docs/fr/guide/essentials/redirect-and-alias.md b/docs/fr/guide/essentials/redirect-and-alias.md index ea39015a1..863f2c940 100644 --- a/docs/fr/guide/essentials/redirect-and-alias.md +++ b/docs/fr/guide/essentials/redirect-and-alias.md @@ -35,7 +35,7 @@ const router = new VueRouter({ }) ``` -Notez que les [intercepteurs de navigation](../advanced/navigation-guards.md) ne sont pas appliqués sur les routes d'où à lieu la redirection mais uniquement sur les routes cibles. Dans l'exemple ci-dessous, ajouter une interception `beforeEnter` ou `beforeLeave` à la route `/a` n'aura aucun effet. +Notez que les [intercepteurs de navigation](../advanced/navigation-guards.md) ne sont pas appliqués sur les routes d'où à lieu la redirection mais uniquement sur les routes cibles. Dans l'exemple ci-dessous, ajouter une interception `beforeEnter` à la route `/a` n'aura aucun effet. Pour d'autres utilisations avancées, jetez un œil à cet [exemple](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js). @@ -43,7 +43,7 @@ Pour d'autres utilisations avancées, jetez un œil à cet [exemple](https://git Une redirection signifie que si l'utilisateur visite `/a`, l'URL va être remplacé par `/b` et concordé avec `/b`. Mais qu'est-ce qu'un alias ? -** Un alias de `/a` en tant que `/b` signifie que lorsque l'utilisateur va visiter `/b`, l'URL va rester `/b`, mais la concordance va se faire comme si l'utilisateur visitait `/a`.** +**Un alias de `/a` en tant que `/b` signifie que lorsque l'utilisateur va visiter `/b`, l'URL va rester `/b`, mais la concordance va se faire comme si l'utilisateur visitait `/a`.** La phase du dessus peut être exprimée dans la configuration de la route de la manière suivante : diff --git a/docs/fr/installation.md b/docs/fr/installation.md index 63a4fdccb..0fc456b1f 100644 --- a/docs/fr/installation.md +++ b/docs/fr/installation.md @@ -2,10 +2,10 @@ ## Téléchargement direct / CDN -[https://unpkg.com/vue-router/dist/vue-router.js](https://unpkg.com/vue-router/dist/vue-router.js) +[https://unpkg.com/vue-router@3/dist/vue-router.js](https://unpkg.com/vue-router@3/dist/vue-router.js) -[Unpkg.com](https://unpkg.com) fournit des liens CDN basés sur npm. Le lien ci-dessus pointera toujours vers la dernière version sur npm. Vous pouvez aussi utiliser un tag ou une version spécifique via un URL comme `https://unpkg.com/vue-router@2.0.0/dist/vue-router.js`. +[Unpkg.com](https://unpkg.com) fournit des liens CDN basés sur npm. Le lien ci-dessus pointera toujours vers la dernière version sur npm. Vous pouvez aussi utiliser un tag ou une version spécifique via un URL comme `https://unpkg.com/vue-router@3.0.0/dist/vue-router.js`. Incluez `vue-router` après Vue et l'installation sera automatique : diff --git a/docs/guide/README.md b/docs/guide/README.md index a6e87ca0a..017faa45f 100644 --- a/docs/guide/README.md +++ b/docs/guide/README.md @@ -1,20 +1,22 @@ # Getting Started - - ::: tip Note +You are reading the documentation of Vue Router 3 **for Vue 2**. If you are working with Vue 3, use the [Vue Router 4 documentation](https://next.router.vuejs.org) instead. + We will be using [ES2015](https://github.com/lukehoban/es6features) in the code samples in the guide. Also, all examples will be using the full version of Vue to make on-the-fly template compilation possible. See more details [here](https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only). ::: -Creating a Single-page Application with Vue + Vue Router is dead simple. With Vue.js, we are already composing our application with components. When adding Vue Router to the mix, all we need to do is map our components to the routes and let Vue Router know where to render them. Here's a basic example: +
    + +Creating a Single-page Application with Vue + Vue Router feels natural: with Vue.js, we are already composing our application with components. When adding Vue Router to the mix, all we need to do is map our components to the routes and let Vue Router know where to render them. Here's a basic example: ## HTML -``` html - - +```html + +

    Hello App!

    @@ -33,7 +35,7 @@ Creating a Single-page Application with Vue + Vue Router is dead simple. With Vu ## JavaScript -``` js +```js // 0. If using a module system (e.g. via vue-cli), import Vue and VueRouter // and then call `Vue.use(VueRouter)`. @@ -75,16 +77,14 @@ By injecting the router, we get access to it as `this.$router` as well as the cu // Home.vue export default { computed: { - username () { + username() { // We will see what `params` is shortly return this.$route.params.username } }, methods: { - goBack () { - window.history.length > 1 - ? this.$router.go(-1) - : this.$router.push('/') + goBack() { + window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/') } } } diff --git a/docs/guide/advanced/data-fetching.md b/docs/guide/advanced/data-fetching.md index b8559c291..bde314f66 100644 --- a/docs/guide/advanced/data-fetching.md +++ b/docs/guide/advanced/data-fetching.md @@ -55,8 +55,11 @@ export default { fetchData () { this.error = this.post = null this.loading = true + const fetchedId = this.$route.params.id // replace `getPost` with your data fetching util / API wrapper - getPost(this.$route.params.id, (err, post) => { + getPost(fetchedId, (err, post) => { + // make sure this request is the last one we did, discard otherwise + if (this.$route.params.id !== fetchedId) return this.loading = false if (err) { this.error = err.toString() diff --git a/docs/guide/advanced/lazy-loading.md b/docs/guide/advanced/lazy-loading.md index 7735a471b..db059d8a0 100644 --- a/docs/guide/advanced/lazy-loading.md +++ b/docs/guide/advanced/lazy-loading.md @@ -1,18 +1,23 @@ # Lazy Loading Routes + + When building apps with a bundler, the JavaScript bundle can become quite large, and thus affect the page load time. It would be more efficient if we can split each route's components into a separate chunk, and only load them when the route is visited. Combining Vue's [async component feature](https://vuejs.org/guide/components.html#Async-Components) and webpack's [code splitting feature](https://webpack.js.org/guides/code-splitting-async/), it's trivially easy to lazy-load route components. First, an async component can be defined as a factory function that returns a Promise (which should resolve to the component itself): -``` js -const Foo = () => Promise.resolve({ /* component definition */ }) +```js +const Foo = () => + Promise.resolve({ + /* component definition */ + }) ``` Second, in webpack 2, we can use the [dynamic import](https://github.com/tc39/proposal-dynamic-import) syntax to indicate a code-split point: -``` js +```js import('./Foo.vue') // returns a Promise ``` @@ -22,25 +27,23 @@ if you are using Babel, you will need to add the [syntax-dynamic-import](https:/ Combining the two, this is how to define an async component that will be automatically code-split by webpack: -``` js +```js const Foo = () => import('./Foo.vue') ``` Nothing needs to change in the route config, just use `Foo` as usual: -``` js +```js const router = new VueRouter({ - routes: [ - { path: '/foo', component: Foo } - ] + routes: [{ path: '/foo', component: Foo }] }) ``` ## Grouping Components in the Same Chunk -Sometimes we may want to group all the components nested under the same route into the same async chunk. To achieve that we need to use [named chunks](https://webpack.js.org/guides/code-splitting-async/#chunk-names) by providing a chunk name using a special comment syntax (requires webpack > 2.4): +Sometimes we may want to group all the components nested under the same route into the same async chunk. To achieve that we need to use [named chunks](https://webpack.js.org/api/module-methods/#magic-comments) by providing a chunk name using a special comment syntax (requires webpack > 2.4): -``` js +```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') diff --git a/docs/guide/advanced/meta.md b/docs/guide/advanced/meta.md index 79845b28d..8cbd97449 100644 --- a/docs/guide/advanced/meta.md +++ b/docs/guide/advanced/meta.md @@ -1,8 +1,8 @@ # Route Meta Fields -You can include a `meta` field when defining a route: +Sometimes, you might want to attach arbitrary information to routes like transition names, who can access the route, etc. This can be achieved through the `meta` property which accepts an object of properties and can be accessed on the route location and navigation guards. You can define `meta` properties like this: -``` js +```js const router = new VueRouter({ routes: [ { @@ -31,7 +31,7 @@ All route records matched by a route are exposed on the `$route` object (and als An example use case is checking for a meta field in the global navigation guard: -``` js +```js router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { // this route requires auth, check if logged in diff --git a/docs/guide/advanced/navigation-failures.md b/docs/guide/advanced/navigation-failures.md new file mode 100644 index 000000000..ff6e2cb36 --- /dev/null +++ b/docs/guide/advanced/navigation-failures.md @@ -0,0 +1,61 @@ +# Navigation Failures + +> New in 3.4.0 + +When using `router-link`, Vue Router calls `router.push` to trigger a navigation. While the expected behavior for most links is to navigate a user to a new page, there are a few situations where users will remain on the same page: + +- Users are already on the page that they are trying to navigate to +- A [navigation guard](./navigation-guards.md) aborts the navigation by calling `next(false)` +- A [navigation guard](./navigation-guards.md) throws an error or calls `next(new Error())` + +When using a `router-link` component, **none of these failures will log an error**. However, if you are using `router.push` or `router.replace`, you might come across an _"Uncaught (in promise) Error"_ message followed by a more specific message in your console. Let's understand how to differentiate _Navigation Failures_. + +::: tip Background story +In v3.2.0, _Navigation Failures_ were exposed through the two optional callbacks of `router.push`: `onComplete` and `onAbort`. Since version 3.1.0, `router.push` and `router.replace` return a _Promise_ if no `onComplete`/`onAbort` callback is provided. This _Promise_ resolves instead of invoking `onComplete` and rejects instead of invoking `onAbort`. +::: + +## Detecting Navigation Failures + +_Navigation Failures_ are `Error` instances with a few extra properties. To check if an error comes from the Router, use the `isNavigationFailure` function: + +```js +import VueRouter from 'vue-router' +const { isNavigationFailure, NavigationFailureType } = VueRouter + +// trying to access the admin page +router.push('/admin').catch(failure => { + if (isNavigationFailure(failure, NavigationFailureType.redirected)) { + // show a small notification to the user + showToast('Login in order to access the admin panel') + } +}) +``` + +::: tip +If you omit the second parameter: `isNavigationFailure(failure)`, it will only check if the error is a _Navigation Failure_. +::: + +## `NavigationFailureType` + +`NavigationFailureType` help developers to differentiate between the various types of _Navigation Failures_. There are four different types: + +- `redirected`: `next(newLocation)` was called inside of a navigation guard to redirect somewhere else. +- `aborted`: `next(false)` was called inside of a navigation guard to the navigation. +- `cancelled`: A new navigation completely took place before the current navigation could finish. e.g. `router.push` was called while waiting inside of a navigation guard. +- `duplicated`: The navigation was prevented because we are already at the target location. + +## _Navigation Failures_'s properties + +All navigation failures expose `to` and `from` properties to reflect the target and current location respectively for the navigation that failed: + +```js +// trying to access the admin page +router.push('/admin').catch(failure => { + if (isNavigationFailure(failure, NavigationFailureType.redirected)) { + failure.to.path // '/admin' + failure.from.path // '/' + } +}) +``` + +In all cases, `to` and `from` are normalized route locations. diff --git a/docs/guide/advanced/navigation-guards.md b/docs/guide/advanced/navigation-guards.md index 5962cae3b..8c132c267 100644 --- a/docs/guide/advanced/navigation-guards.md +++ b/docs/guide/advanced/navigation-guards.md @@ -6,9 +6,11 @@ Remember that **params or query changes won't trigger enter/leave navigation gua ## Global Before Guards + + You can register global before guards using `router.beforeEach`: -``` js +```js const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { @@ -34,7 +36,24 @@ Every guard function receives three arguments: - **`next(error)`**: (2.4.0+) if the argument passed to `next` is an instance of `Error`, the navigation will be aborted and the error will be passed to callbacks registered via [`router.onError()`](../../api/#router-onerror). -**Make sure to always call the `next` function, otherwise the hook will never be resolved.** +**Make sure that the `next` function is called exactly once in any given pass through the navigation guard. It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors.** Here is an example of redirecting to user to `/login` if they are not authenticated: + +```js +// BAD +router.beforeEach((to, from, next) => { + if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' }) + // if the user is not authenticated, `next` is called twice + next() +}) +``` + +```js +// GOOD +router.beforeEach((to, from, next) => { + if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' }) + else next() +}) +``` ## Global Resolve Guards @@ -44,7 +63,7 @@ You can register a global guard with `router.beforeResolve`. This is similar to You can also register global after hooks, however unlike guards, these hooks do not get a `next` function and cannot affect the navigation: -``` js +```js router.afterEach((to, from) => { // ... }) @@ -54,7 +73,7 @@ router.afterEach((to, from) => { You can define `beforeEnter` guards directly on a route's configuration object: -``` js +```js const router = new VueRouter({ routes: [ { @@ -78,23 +97,23 @@ Finally, you can directly define route navigation guards inside route components - `beforeRouteUpdate` - `beforeRouteLeave` -``` js +```js const Foo = { template: `...`, - beforeRouteEnter (to, from, next) { + beforeRouteEnter(to, from, next) { // called before the route that renders this component is confirmed. // does NOT have access to `this` component instance, // because it has not been created yet when this guard is called! }, - beforeRouteUpdate (to, from, next) { - // called when the route that renders this component has changed, - // but this component is reused in the new route. + beforeRouteUpdate(to, from, next) { + // called when the route that renders this component has changed. + // This component being reused (by using an explicit `key`) in the new route or not doesn't change anything. // For example, for a route with dynamic params `/foo/:id`, when we // navigate between `/foo/1` and `/foo/2`, the same `Foo` component instance - // will be reused, and this hook will be called when that happens. + // will be reused (unless you provided a `key` to ``), and this hook will be called when that happens. // has access to `this` component instance. }, - beforeRouteLeave (to, from, next) { + beforeRouteLeave(to, from, next) { // called when the route that renders this component is about to // be navigated away from. // has access to `this` component instance. @@ -106,7 +125,7 @@ The `beforeRouteEnter` guard does **NOT** have access to `this`, because the gua However, you can access the instance by passing a callback to `next`. The callback will be called when the navigation is confirmed, and the component instance will be passed to the callback as the argument: -``` js +```js beforeRouteEnter (to, from, next) { next(vm => { // access to component instance via `vm` @@ -114,7 +133,7 @@ beforeRouteEnter (to, from, next) { } ``` -Note that `beforeRouteEnter` is the only guard that supports passing a callback to `next`. For `beforeRouteUpdate` and `beforeRouteLeave`, `this` is already available, so passing a callback is unnecessary and therefore *not supported*: +Note that `beforeRouteEnter` is the only guard that supports passing a callback to `next`. For `beforeRouteUpdate` and `beforeRouteLeave`, `this` is already available, so passing a callback is unnecessary and therefore _not supported_: ```js beforeRouteUpdate (to, from, next) { @@ -137,10 +156,22 @@ beforeRouteLeave (to, from, next) { } ``` +If you are using mixins that add in-component navigation guards, make sure to add the mixin **after installing the router plugin**: + +```js +Vue.use(Router) + +Vue.mixin({ + beforeRouteUpdate(to, from, next) { + // ... + } +}) +``` + ## The Full Navigation Resolution Flow 1. Navigation triggered. -2. Call leave guards in deactivated components. +2. Call `beforeRouteLeave` guards in deactivated components. 3. Call global `beforeEach` guards. 4. Call `beforeRouteUpdate` guards in reused components. 5. Call `beforeEnter` in route configs. diff --git a/docs/guide/advanced/scroll-behavior.md b/docs/guide/advanced/scroll-behavior.md index d58d797b2..037329426 100644 --- a/docs/guide/advanced/scroll-behavior.md +++ b/docs/guide/advanced/scroll-behavior.md @@ -1,12 +1,14 @@ # Scroll Behavior + + When using client-side routing, we may want to scroll to top when navigating to a new route, or preserve the scrolling position of history entries just like real page reload does. `vue-router` allows you to achieve these and even better, allows you to completely customize the scroll behavior on route navigation. **Note: this feature only works if the browser supports `history.pushState`.** When creating the router instance, you can provide the `scrollBehavior` function: -``` js +```js const router = new VueRouter({ routes: [...], scrollBehavior (to, from, savedPosition) { @@ -26,7 +28,7 @@ If a falsy value or an empty object is returned, no scrolling will happen. For example: -``` js +```js scrollBehavior (to, from, savedPosition) { return { x: 0, y: 0 } } @@ -36,7 +38,7 @@ This will simply make the page scroll to top for all route navigations. Returning the `savedPosition` will result in a native-like behavior when navigating with back/forward buttons: -``` js +```js scrollBehavior (to, from, savedPosition) { if (savedPosition) { return savedPosition @@ -48,7 +50,7 @@ scrollBehavior (to, from, savedPosition) { If you want to simulate the "scroll to anchor" behavior: -``` js +```js scrollBehavior (to, from, savedPosition) { if (to.hash) { return { @@ -67,7 +69,7 @@ We can also use [route meta fields](meta.md) to implement fine-grained scroll be You can also return a Promise that resolves to the desired position descriptor: -``` js +```js scrollBehavior (to, from, savedPosition) { return new Promise((resolve, reject) => { setTimeout(() => { @@ -78,3 +80,18 @@ scrollBehavior (to, from, savedPosition) { ``` It's possible to hook this up with events from a page-level transition component to make the scroll behavior play nicely with your page transitions, but due to the possible variance and complexity in use cases, we simply provide this primitive to enable specific userland implementations. + +## Smooth Scrolling + +You can enable native smooth scrolling for [browsers supporting it](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior) by simply adding the `behavior` option to the object returned inside `scrollBehavior`: + +```js +scrollBehavior (to, from, savedPosition) { + if (to.hash) { + return { + selector: to.hash, + behavior: 'smooth', + } + } +} +``` diff --git a/docs/guide/advanced/transitions.md b/docs/guide/advanced/transitions.md index 269d3cc23..0b8a937df 100644 --- a/docs/guide/advanced/transitions.md +++ b/docs/guide/advanced/transitions.md @@ -1,20 +1,22 @@ # Transitions + + Since the `` is essentially a dynamic component, we can apply transition effects to it the same way using the `` component: -``` html +```html ``` -[All transition APIs](https://vuejs.org/guide/transitions.html) work the same here. +[All transition APIs](https://v2.vuejs.org/v2/guide/transitions.html) work the same here. ## Per-Route Transition The above usage will apply the same transition for all routes. If you want each route's component to have different transitions, you can instead use `` with different names inside each route component: -``` js +```js const Foo = { template: ` @@ -36,14 +38,14 @@ const Bar = { It is also possible to determine the transition to use dynamically based on the relationship between the target route and current route: -``` html +```html ``` -``` js +```js // then, in the parent component, // watch the `$route` to determine the transition to use watch: { diff --git a/docs/guide/essentials/dynamic-matching.md b/docs/guide/essentials/dynamic-matching.md index f08c6dc91..c8ced5875 100644 --- a/docs/guide/essentials/dynamic-matching.md +++ b/docs/guide/essentials/dynamic-matching.md @@ -1,8 +1,10 @@ # Dynamic Route Matching + + Very often we will need to map routes with the given pattern to the same component. For example we may have a `User` component which should be rendered for all users but with different user IDs. In `vue-router` we can use a dynamic segment in the path to achieve that: -``` js +```js const User = { template: '
    User
    ' } @@ -19,7 +21,7 @@ Now URLs like `/user/foo` and `/user/bar` will both map to the same route. A dynamic segment is denoted by a colon `:`. When a route is matched, the value of the dynamic segments will be exposed as `this.$route.params` in every component. Therefore, we can render the current user ID by updating `User`'s template to this: -``` js +```js const User = { template: '
    User {{ $route.params.id }}
    ' } @@ -29,9 +31,9 @@ You can check out a live example [here](https://jsfiddle.net/yyx990803/4xfa2f19/ You can have multiple dynamic segments in the same route, and they will map to corresponding fields on `$route.params`. Examples: -| pattern | matched path | $route.params | -|---------|------|--------| -| /user/:username | /user/evan | `{ username: 'evan' }` | +| pattern | matched path | \$route.params | +| ----------------------------- | ------------------- | -------------------------------------- | +| /user/:username | /user/evan | `{ username: 'evan' }` | | /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` | In addition to `$route.params`, the `$route` object also exposes other useful information such as `$route.query` (if there is a query in the URL), `$route.hash`, etc. You can check out the full details in the [API Reference](../../api/#the-route-object). @@ -42,11 +44,11 @@ One thing to note when using routes with params is that when the user navigates To react to params changes in the same component, you can simply watch the `$route` object: -``` js +```js const User = { template: '...', watch: { - '$route' (to, from) { + $route(to, from) { // react to route changes... } } @@ -55,10 +57,10 @@ const User = { Or, use the `beforeRouteUpdate` [navigation guard](../advanced/navigation-guards.html) introduced in 2.2: -``` js +```js const User = { template: '...', - beforeRouteUpdate (to, from, next) { + beforeRouteUpdate(to, from, next) { // react to route changes... // don't forget to call next() } @@ -97,7 +99,7 @@ this.$route.params.pathMatch // '/non-existing' ## Advanced Matching Patterns -`vue-router` uses [path-to-regexp](https://github.com/pillarjs/path-to-regexp) as its path matching engine, so it supports many advanced matching patterns such as optional dynamic segments, zero or more / one or more requirements, and even custom regex patterns. Check out its [documentation](https://github.com/pillarjs/path-to-regexp#parameters) for these advanced patterns, and [this example](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) of using them in `vue-router`. +`vue-router` uses [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) as its path matching engine, so it supports many advanced matching patterns such as optional dynamic segments, zero or more / one or more requirements, and even custom regex patterns. Check out its [documentation](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters) for these advanced patterns, and [this example](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) of using them in `vue-router`. ## Matching Priority diff --git a/docs/guide/essentials/history-mode.md b/docs/guide/essentials/history-mode.md index 759c9ea16..ed27c1baa 100644 --- a/docs/guide/essentials/history-mode.md +++ b/docs/guide/essentials/history-mode.md @@ -19,9 +19,14 @@ Not to worry: To fix the issue, all you need to do is add a simple catch-all fal ## Example Server Configurations +**Note**: The following examples assume you are serving your app from the root folder. If you deploy to a subfolder, you should use [the `publicPath` option of Vue CLI](https://cli.vuejs.org/config/#publicpath) and the related [`base` property of the router](https://router.vuejs.org/api/#base). You also need to adjust the examples below to use the subfolder instead of the root folder (e.g. replacing `RewriteBase /` with `RewriteBase /name-of-your-subfolder/`). + #### Apache ```apache + + Options -MultiViews + RewriteEngine On RewriteBase / @@ -50,9 +55,9 @@ const fs = require('fs') const httpPort = 80 http.createServer((req, res) => { - fs.readFile('index.htm', 'utf-8', (err, content) => { + fs.readFile('index.html', 'utf-8', (err, content) => { if (err) { -      console.log('We cannot open "index.htm" file.') +      console.log('We cannot open "index.html" file.') } res.writeHead(200, { @@ -95,7 +100,13 @@ For Node.js/Express, consider using [connect-history-api-fallback middleware](ht ``` -#### Caddy +#### Caddy v2 + +``` +try_files {path} / +``` + +#### Caddy v1 ``` rewrite { @@ -130,7 +141,11 @@ There is a caveat to this: Your server will no longer report 404 errors as all n const router = new VueRouter({ mode: 'history', routes: [ - { path: '*', component: NotFoundComponent } + { + path: '/:catchAll(.*)', + component: NotFoundComponent, + name: 'NotFound' + } ] }) ``` diff --git a/docs/guide/essentials/named-routes.md b/docs/guide/essentials/named-routes.md index 297457c52..2e77ed7cf 100644 --- a/docs/guide/essentials/named-routes.md +++ b/docs/guide/essentials/named-routes.md @@ -1,8 +1,10 @@ # Named Routes + + Sometimes it is more convenient to identify a route with a name, especially when linking to a route or performing navigations. You can give a route a name in the `routes` options while creating the Router instance: -``` js +```js const router = new VueRouter({ routes: [ { @@ -16,14 +18,14 @@ const router = new VueRouter({ To link to a named route, you can pass an object to the `router-link` component's `to` prop: -``` html +```html User ``` -This is the exact same object used programatically with `router.push()`: +This is the exact same object used programmatically with `router.push()`: -``` js -router.push({ name: 'user', params: { userId: 123 }}) +```js +router.push({ name: 'user', params: { userId: 123 } }) ``` In both cases, the router will navigate to the path `/user/123`. diff --git a/docs/guide/essentials/named-views.md b/docs/guide/essentials/named-views.md index c848b08aa..d426ead04 100644 --- a/docs/guide/essentials/named-views.md +++ b/docs/guide/essentials/named-views.md @@ -48,7 +48,7 @@ It is possible to create complex layouts using named views with nested views. Wh - `UserSettings` is the view component - `UserEmailsSubscriptions`, `UserProfile`, `UserProfilePreview` are nested view components -**Note**: _Let's forget about how the HTML/CSS should look like to represent such layout and focus on the components used_ +**Note**: _Let's forget about how the HTML/CSS should look like to represent such layout and focus on the components used._ The `