Skip to content

Commit e0de642

Browse files
committed
docs: meta, scroll, lazy loading
1 parent 3351760 commit e0de642

File tree

5 files changed

+147
-66
lines changed

5 files changed

+147
-66
lines changed

docs/en/SUMMARY.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
- [Named Routes](essentials/named-routes.md)
1313
- [Named Views](essentials/named-views.md)
1414
- [Redirect and Alias](essentials/redirect-and-alias.md)
15-
- [Server Config for History Mode](essentials/server.md)
15+
- [HTML5 History Mode](essentials/history-mode.md)
1616
- Advanced
1717
- [Navigation Hooks](advanced/navigation-guards.md)
18+
- [Route Meta Fields](advanced/meta.md)
1819
- [Transitions](advanced/transitions.md)
1920
- [Data Fetching](advanced/data-fetching.md)
2021
- [Scroll Behavior](advanced/scroll-behavior.md)

docs/en/advanced/lazy-loading.md

Lines changed: 23 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,45 @@
11
# Lazy Loading Routes
22

3-
When you are using bundlers like Webpack or Browserify, it's trivially easy to
4-
lazy-load a route component using Vue.js' built-in
5-
[async component functionality](http://vuejs.org/guide/components.html#Async-Components).
6-
Instead of directly defining your route component, you define it as a function
7-
that will asynchronously resolve the actual component definition:
3+
When building apps with a bundler, the JavaScript bundle can become quite large and thus affecting 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.
84

9-
``` js
10-
const router = new VueRouter({
11-
routes: [
12-
{
13-
path: '/async',
14-
component: function (resolve) {
15-
// somehow retrieve your component definition from server...
16-
resolve(MyComponent)
17-
}
18-
}
19-
]
20-
})
21-
```
5+
Combining Vue's [async component feature](http://vuejs.org/guide/components.html#Async-Components) and Webpack's [code splitting feature](https://webpack.github.io/docs/code-splitting.html), it's trivially easy to
6+
lazy-load route components.
227

23-
Now, manually handling component retrieval is less than ideal, but bundlers like
24-
Webpack & Browserify both provides ways to make it easier.
8+
All we need to do is defining our route components as async components:
259

26-
### Webpack
10+
``` js
11+
const Foo = resolve => {
12+
// require.ensure is Webpack's special syntax for a code-split point.
13+
require.ensure(['./Foo.vue'], () => {
14+
resolve(require('./Foo.vue'))
15+
})
16+
}
17+
```
2718

28-
Webpack has built-in support for async code-splitting. You can use the AMD-like
29-
`require` syntax in your code to indicate an async code-split point:
19+
There's also an alternative code-split syntax using AMD style require, so this can be simplified to:
3020

3121
``` js
32-
require(['./MyComponent.vue'], function (MyComponent) {
33-
// code here runs after MyComponent.vue is asynchronously loaded.
34-
})
22+
const Foo = resolve => require(['./Foo.vue'], resolve)
3523
```
3624

37-
Combined with the router it can simply look like this:
25+
Nothing needs to change in the route config, just use `Foo` as usual:
3826

3927
``` js
4028
const router = new VueRouter({
4129
routes: [
42-
{
43-
path: '/async',
44-
component: function (resolve) {
45-
require(['./MyComponent.vue'], resolve)
46-
}
47-
}
30+
{ path: '/foo', component: Foo }
4831
]
4932
})
5033
```
5134

52-
Now, `MyComponent.vue`, along with any dependencies that are only used by itself,
53-
will be loaded asynchronously only when the route `/async` needs to be rendered.
54-
55-
### Browserify
35+
### Grouping Components in the Same Chunk
5636

57-
TODO make this part as easy as wepack's
58-
59-
It's a bit more tricky to achieve the same with Browserify, but it's possible
60-
with the
61-
[`partition-bundle` plugin](https://github.com/substack/browserify-handbook/blob/master/readme.markdown#partition-bundle).
62-
You will have to manually declare your bundle mappings in a `json` file:
63-
64-
``` json
65-
{
66-
"main.js": ["./main.js"],
67-
"my-component.js": ["./MyComponent.vue"]
68-
}
69-
```
70-
71-
Then in `main.js` you would do something similar, using the `loadjs` function instead of `require`:
37+
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.github.io/docs/code-splitting.html#named-chunks) by providing a chunk name to `require.ensure` as the 3rd argument:
7238

7339
``` js
74-
const router = new VueRouter({
75-
routes: [
76-
{
77-
path: '/async',
78-
component: function (resolve) {
79-
loadjs(['./MyComponent.vue'], resolve)
80-
}
81-
}
82-
]
83-
})
40+
const Foo = r => require.ensure([], () => r(require('./Foo.vue')), 'group-foo')
41+
const Bar = r => require.ensure([], () => r(require('./Bar.vue')), 'group-foo')
42+
const Baz = r => require.ensure([], () => r(require('./Baz.vue')), 'group-foo')
8443
```
44+
45+
Webpack will group any async module with the same chunk name into the same async chunk - this also means we don't need to explicitly list dependencies for `require.ensure` anymore (thus passing an empty array).

docs/en/advanced/meta.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Route Meta Fields
2+
3+
You can include a `meta` field when defining a route:
4+
5+
``` js
6+
const router = new VueRouter({
7+
routes: [
8+
{
9+
path: '/foo',
10+
component: Foo,
11+
children: [
12+
{
13+
path: 'bar',
14+
component: Bar,
15+
// a meta field
16+
meta: { requiresAuth: true }
17+
}
18+
]
19+
}
20+
]
21+
})
22+
```
23+
24+
So how do we access this `meta` field?
25+
26+
First, each route object in the `routes` configuration is called a **route record**. Route records may be nested. Therefore when a route is matched, it can potentially match more than one route record.
27+
28+
For example, with the above route config, the URL `/foo/bar` will match both the parent route record and the child route record.
29+
30+
All route records matched by a route are exposed on the `$route` object (and also route objects in navigation guards) as the `$route.matched` Array. Therefore, we will need to iterate over `$route.matched` to check for meta fields in route records.
31+
32+
An example use case is checking for a meta field in the global navigation guard:
33+
34+
``` js
35+
router.beforeEach((route, redirect, next) => {
36+
if (route.matched.some(record => record.meta.requiresAuth)) {
37+
// this route requires auth, check if logged in
38+
// if not, redirect to login page.
39+
if (!auth.loggedIn()) {
40+
redirect({
41+
path: '/login',
42+
query: { redirect: route.fullPath }
43+
})
44+
} else {
45+
next()
46+
}
47+
} else {
48+
next()
49+
}
50+
})
51+
```

docs/en/advanced/scroll-behavior.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Scroll Behavior
2+
3+
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.
4+
5+
**Note: this feature only works in HTML5 history mode.**
6+
7+
When creating the router instance, you can provide the `scrollBehavior` function:
8+
9+
``` js
10+
const router = new VueRouter({
11+
routes: [...],
12+
scrollBehavior (to, from, savedPosition) {
13+
// return desired position
14+
}
15+
})
16+
```
17+
18+
The `scrollBehavior` function receives the `to` and `from` route objects. The third argument, `savedPosition`, is only available if this is a `popstate` navigation (triggered by the browser's back/forward buttons).
19+
20+
The function can return a scroll position object. The object could be in the form of:
21+
22+
- `{ x: number, y: number }`
23+
- `{ selector: string }`
24+
25+
If a falsy value or an empty object is returned, no scrolling will happen.
26+
27+
For example:
28+
29+
``` js
30+
scrollBehavior (to, from, savedPosition) {
31+
return { x: 0, y: 0 }
32+
}
33+
```
34+
35+
This will simply make the page scroll to top for all route navigations.
36+
37+
Returning the `savedPosition` will result in a native-like behavior when navigating with back/forward buttons:
38+
39+
``` js
40+
scrollBehavior (to, from, savedPosition) {
41+
if (savedPosition) {
42+
return savedPosition
43+
} else {
44+
return { x: 0, y: 0 }
45+
}
46+
}
47+
```
48+
49+
If you want to simulate the "scroll to anchor" behavior:
50+
51+
``` js
52+
scrollBehavior (to, from, savedPosition) {
53+
if (to.hash) {
54+
return {
55+
selector: to.hash
56+
}
57+
}
58+
}
59+
```
60+
61+
We can also use [route meta fields](meta.md) to implement fine-grained scroll behavior control. Check out a full example [here](https://github.com/vuejs/vue-router/blob/next/examples/scroll-behavior/app.js).

docs/en/essentials/server.md renamed to docs/en/essentials/history-mode.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
# Server Configuration for History Mode
1+
# HTML5 History Mode
22

33
The default mode for `vue-router` is hash mode - it uses the URL hash to simulate a full URL so that the page won't be reloaded when the URL changes.
44

5-
To get rid of the ugly hash, we can use the HTML5 `history.pushState` API to achieve URL navigation without page reload. But for this mode to work properly, you need to configure your server properly.
5+
To get rid of the ugly hash, we can use the router's **history mode**, which leverages the `history.pushState` API to achieve URL navigation without page reload:
66

7-
Because when using history mode, the URL will look like a normal url, e.g. `http://yoursite.com/user/id`. Since our app is a single page client side app, without proper server configuration the users will get a 404 if they visit that URL directly.
7+
``` js
8+
const router = new VueRouter({
9+
mode: 'history',
10+
routes: [...]
11+
})
12+
```
13+
14+
But for this mode to work properly, you need to configure your server properly. When using history mode, the URL will look like a normal url, e.g. `http://yoursite.com/user/id`. Since our app is a single page client side app, without proper server configuration the users will get a 404 if they visit that URL directly.
815

916
Therefore you need to add a catch-all fallback route to your server: if the URL doesn't match any static assets, it should serve the same `index.html` page that your app lives in.
1017

0 commit comments

Comments
 (0)