|
2 | 2 |
|
3 | 3 | ## Official Router
|
4 | 4 |
|
| 5 | +<!-- TODO update links --> |
| 6 | + |
5 | 7 | For most Single Page Applications, it's recommended to use the officially-supported [vue-router library](https://github.com/vuejs/vue-router-next). For more details, see vue-router's [documentation](https://next.router.vuejs.org/).
|
6 | 8 |
|
7 | 9 | ## Simple Routing from Scratch
|
8 | 10 |
|
9 |
| -If you only need very simple routing and do not wish to involve a full-featured router library, you can do so by dynamically rendering a page-level component like this: |
| 11 | +If you only need very simple routing and do not wish to involve a full-featured router library, you can do so with [Dynamic Components](/guide/essentials/component-basics.html#dynamic-components) and update the current component state by listening to browser [`hashchange` events](https://developer.mozilla.org/en-US/docs/Web/API/Window/hashchange_event) or using the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History). |
| 12 | + |
| 13 | +Here's a bare-bone example: |
10 | 14 |
|
11 |
| -```js |
12 |
| -const { createApp, h } = Vue |
| 15 | +<div class="composition-api"> |
13 | 16 |
|
14 |
| -const NotFoundComponent = { template: '<p>Page not found</p>' } |
15 |
| -const HomeComponent = { template: '<p>Home page</p>' } |
16 |
| -const AboutComponent = { template: '<p>About page</p>' } |
| 17 | +```vue |
| 18 | +<script setup> |
| 19 | +import { ref, computed } from 'vue' |
| 20 | +import Home from './Home.vue' |
| 21 | +import About from './About.vue' |
| 22 | +import NotFound from './NotFound.vue' |
17 | 23 |
|
18 | 24 | const routes = {
|
19 |
| - '/': HomeComponent, |
20 |
| - '/about': AboutComponent |
| 25 | + '/': Home, |
| 26 | + '/about': About |
21 | 27 | }
|
22 | 28 |
|
23 |
| -const SimpleRouter = { |
24 |
| - data: () => ({ |
25 |
| - currentRoute: window.___location.pathname |
26 |
| - }), |
| 29 | +const currentPath = ref(window.___location.hash) |
| 30 | +
|
| 31 | +window.addEventListener('hashchange', () => { |
| 32 | + currentPath.value = window.___location.hash |
| 33 | +}) |
| 34 | +
|
| 35 | +const currentView = computed(() => { |
| 36 | + return routes[currentPath.value.slice(1) || '/'] || NotFound |
| 37 | +}) |
| 38 | +</script> |
| 39 | +
|
| 40 | +<template> |
| 41 | + <a href="#/">Home</a> | |
| 42 | + <a href="#/about">About</a> | |
| 43 | + <a href="#/non-existent-path">Broken Link</a> |
| 44 | + <component :is="currentView" /> |
| 45 | +</template> |
| 46 | +``` |
| 47 | + |
| 48 | +[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiwgY29tcHV0ZWQgfSBmcm9tICd2dWUnXG5pbXBvcnQgSG9tZSBmcm9tICcuL0hvbWUudnVlJ1xuaW1wb3J0IEFib3V0IGZyb20gJy4vQWJvdXQudnVlJ1xuaW1wb3J0IE5vdEZvdW5kIGZyb20gJy4vTm90Rm91bmQudnVlJ1xuXG5jb25zdCByb3V0ZXMgPSB7XG4gICcvJzogSG9tZSxcbiAgJy9hYm91dCc6IEFib3V0XG59XG5cbmNvbnN0IGN1cnJlbnRQYXRoID0gcmVmKHdpbmRvdy5sb2NhdGlvbi5oYXNoKVxuXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignaGFzaGNoYW5nZScsICgpID0+IHtcbiAgY3VycmVudFBhdGgudmFsdWUgPSB3aW5kb3cubG9jYXRpb24uaGFzaFxufSlcblxuY29uc3QgY3VycmVudFZpZXcgPSBjb21wdXRlZCgoKSA9PiB7XG4gIHJldHVybiByb3V0ZXNbY3VycmVudFBhdGgudmFsdWUuc2xpY2UoMSkgfHwgJy8nXSB8fCBOb3RGb3VuZFxufSlcbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxhIGhyZWY9XCIjL1wiPkhvbWU8L2E+IHxcbiAgPGEgaHJlZj1cIiMvYWJvdXRcIj5BYm91dDwvYT4gfFxuICA8YSBocmVmPVwiIy9ub24tZXhpc3RlbnQtcGF0aFwiPkJyb2tlbiBMaW5rPC9hPlxuICA8Y29tcG9uZW50IDppcz1cImN1cnJlbnRWaWV3XCIgLz5cbjwvdGVtcGxhdGU+IiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwidnVlXCI6IFwiaHR0cHM6Ly9zZmMudnVlanMub3JnL3Z1ZS5ydW50aW1lLmVzbS1icm93c2VyLmpzXCJcbiAgfVxufSIsIkhvbWUudnVlIjoiPHRlbXBsYXRlPlxuICA8aDE+SG9tZTwvaDE+XG48L3RlbXBsYXRlPiIsIkFib3V0LnZ1ZSI6Ijx0ZW1wbGF0ZT5cbiAgPGgxPkFib3V0PC9oMT5cbjwvdGVtcGxhdGU+IiwiTm90Rm91bmQudnVlIjoiPHRlbXBsYXRlPlxuICA8aDE+NDA0PC9oMT5cbjwvdGVtcGxhdGU+In0=) |
| 49 | + |
| 50 | +</div> |
| 51 | + |
| 52 | +<div class="options-api"> |
27 | 53 |
|
| 54 | +```vue |
| 55 | +<script> |
| 56 | +import Home from './Home.vue' |
| 57 | +import About from './About.vue' |
| 58 | +import NotFound from './NotFound.vue' |
| 59 | +
|
| 60 | +const routes = { |
| 61 | + '/': Home, |
| 62 | + '/about': About |
| 63 | +} |
| 64 | +
|
| 65 | +export default { |
| 66 | + data() { |
| 67 | + return { |
| 68 | + currentPath: window.___location.hash |
| 69 | + } |
| 70 | + }, |
28 | 71 | computed: {
|
29 |
| - CurrentComponent() { |
30 |
| - return routes[this.currentRoute] || NotFoundComponent |
| 72 | + currentView() { |
| 73 | + return routes[this.currentPath.slice(1) || '/'] || NotFound |
31 | 74 | }
|
32 | 75 | },
|
33 |
| - |
34 |
| - render() { |
35 |
| - return h(this.CurrentComponent) |
| 76 | + mounted() { |
| 77 | + window.addEventListener('hashchange', () => { |
| 78 | + this.currentPath = window.___location.hash |
| 79 | + }) |
36 | 80 | }
|
37 | 81 | }
|
| 82 | +</script> |
38 | 83 |
|
39 |
| -createApp(SimpleRouter).mount('#app') |
| 84 | +<template> |
| 85 | + <a href="#/">Home</a> | |
| 86 | + <a href="#/about">About</a> | |
| 87 | + <a href="#/non-existent-path">Broken Link</a> |
| 88 | + <component :is="currentView" /> |
| 89 | +</template> |
40 | 90 | ```
|
41 | 91 |
|
42 |
| -Combined with the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API), you can build a very basic but fully-functional client-side router. To see that in practice, check out [this example app](https://github.com/phanan/vue-3.0-simple-routing-example). |
43 |
| - |
44 |
| -## Integrating 3rd-Party Routers |
| 92 | +[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmltcG9ydCBIb21lIGZyb20gJy4vSG9tZS52dWUnXG5pbXBvcnQgQWJvdXQgZnJvbSAnLi9BYm91dC52dWUnXG5pbXBvcnQgTm90Rm91bmQgZnJvbSAnLi9Ob3RGb3VuZC52dWUnXG5cbmNvbnN0IHJvdXRlcyA9IHtcbiAgJy8nOiBIb21lLFxuICAnL2Fib3V0JzogQWJvdXRcbn1cblxuZXhwb3J0IGRlZmF1bHQge1xuICBkYXRhKCkge1xuICAgIHJldHVybiB7XG4gICAgICBjdXJyZW50UGF0aDogd2luZG93LmxvY2F0aW9uLmhhc2hcbiAgICB9XG4gIH0sXG4gIGNvbXB1dGVkOiB7XG4gICAgY3VycmVudFZpZXcoKSB7XG4gICAgICByZXR1cm4gcm91dGVzW3RoaXMuY3VycmVudFBhdGguc2xpY2UoMSkgfHwgJy8nXSB8fCBOb3RGb3VuZFxuICAgIH1cbiAgfSxcbiAgbW91bnRlZCgpIHtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignaGFzaGNoYW5nZScsICgpID0+IHtcblx0XHQgIHRoaXMuY3VycmVudFBhdGggPSB3aW5kb3cubG9jYXRpb24uaGFzaFxuXHRcdH0pXG4gIH1cbn1cbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxhIGhyZWY9XCIjL1wiPkhvbWU8L2E+IHxcbiAgPGEgaHJlZj1cIiMvYWJvdXRcIj5BYm91dDwvYT4gfFxuICA8YSBocmVmPVwiIy9ub24tZXhpc3RlbnQtcGF0aFwiPkJyb2tlbiBMaW5rPC9hPlxuICA8Y29tcG9uZW50IDppcz1cImN1cnJlbnRWaWV3XCIgLz5cbjwvdGVtcGxhdGU+IiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwidnVlXCI6IFwiaHR0cHM6Ly9zZmMudnVlanMub3JnL3Z1ZS5ydW50aW1lLmVzbS1icm93c2VyLmpzXCJcbiAgfVxufSIsIkhvbWUudnVlIjoiPHRlbXBsYXRlPlxuICA8aDE+SG9tZTwvaDE+XG48L3RlbXBsYXRlPiIsIkFib3V0LnZ1ZSI6Ijx0ZW1wbGF0ZT5cbiAgPGgxPkFib3V0PC9oMT5cbjwvdGVtcGxhdGU+IiwiTm90Rm91bmQudnVlIjoiPHRlbXBsYXRlPlxuICA8aDE+NDA0PC9oMT5cbjwvdGVtcGxhdGU+In0=) |
45 | 93 |
|
46 |
| -If there's a 3rd-party router you prefer to use, such as [Page.js](https://github.com/visionmedia/page.js) or [Director](https://github.com/flatiron/director), integration is [similarly straightforward](https://github.com/phanan/vue-3.0-simple-routing-example/compare/master...pagejs). Here's a [complete example](https://github.com/phanan/vue-3.0-simple-routing-example/tree/pagejs) using Page.js. |
| 94 | +</div> |
0 commit comments