Skip to content

Commit 2288d83

Browse files
bfangeryyx990803
authored andcommitted
New feature: Passing props to components from vue-router (#973)
* Let the selenium-server and chromedriver packages determine the paths Makes it easier to upgrade to those packages. * Feature: routeConfig.props - Passing props to a component * inlined hasProp + cached the regex literal * Simplied the { props:true } behaviour which is now very predicable. * Updated docs * Updated docs + re-enabled props functionality
1 parent beef8d0 commit 2288d83

File tree

12 files changed

+194
-1
lines changed

12 files changed

+194
-1
lines changed

docs/en/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- [Named Routes](essentials/named-routes.md)
1414
- [Named Views](essentials/named-views.md)
1515
- [Redirect and Alias](essentials/redirect-and-alias.md)
16+
- [Passing props](essentials/passing-props.md)
1617
- [HTML5 History Mode](essentials/history-mode.md)
1718
- Advanced
1819
- [Navigation Guards](advanced/navigation-guards.md)

docs/en/api/options.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
name?: string; // for named routes
1414
components?: { [name: string]: Component }; // for named views
1515
redirect?: string | Location | Function;
16+
props?: boolean | string | Function;
1617
alias?: string | Array<string>;
1718
children?: Array<RouteConfig>; // for nested routes
1819
beforeEnter?: (to: Route, from: Route, next: Function) => void;

docs/en/essentials/passing-props.md

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Passing props
2+
3+
Using `$route` in your component creates a tight coupling with the route which limits the flexibility of the component as it can only be used on certain urls.
4+
5+
To decouple this component from the router use props:
6+
7+
**❌ Coupled to $route**
8+
9+
``` js
10+
const User = {
11+
template: '<div>User {{ $route.params.id }}</div>'
12+
}
13+
const router = new VueRouter({
14+
routes: [
15+
{ path: '/user/:id', component: User }
16+
]
17+
})
18+
```
19+
20+
**👍 Decoupled with props**
21+
22+
``` js
23+
const User = {
24+
props: ['id'],
25+
template: '<div>User {{ id }}</div>'
26+
}
27+
const router = new VueRouter({
28+
routes: [
29+
{ path: '/user/:id', component: User, props: true }
30+
]
31+
})
32+
```
33+
34+
This allows you to use the component anywhere, which makes the component easier to reuse and test.
35+
36+
### Boolean mode
37+
38+
When props is set to true, the route.params will be set as the component props.
39+
40+
### Object mode
41+
42+
When props is an object, this will be set as the component props as-is.
43+
Useful for when the props are static.
44+
45+
``` js
46+
const router = new VueRouter({
47+
routes: [
48+
{ path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
49+
]
50+
})
51+
```
52+
53+
### Function mode
54+
55+
You can create a function that returns props.
56+
This allows you to to cast the parameter to another type, combine static values with route-based values, etc.
57+
58+
``` js
59+
const router = new VueRouter({
60+
routes: [
61+
{ path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }
62+
]
63+
})
64+
```
65+
66+
The url: `/search?q=vue` would pass `{query: "vue"}` as props to the SearchUser component.
67+
68+
Try to keep the props function stateless, as it's only evaluated on route changes.
69+
Use a wrapper component if you need state to define the props, that way vue can react to state changes.
70+
71+
72+
For advanced usage, checkout the [example](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js).

examples/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ <h1>Vue Router Examples</h1>
1515
<li><a href="route-matching">Route Matching</a></li>
1616
<li><a href="active-links">Active Links</a></li>
1717
<li><a href="redirect">Redirect</a></li>
18+
<li><a href="route-props">Route Props</a></li>
1819
<li><a href="route-alias">Route Alias</a></li>
1920
<li><a href="transitions">Transitions</a></li>
2021
<li><a href="data-fetching">Data Fetching</a></li>

examples/route-props/Hello.vue

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<template>
2+
<div>
3+
<h2 class="hello">Hello {{name}}</h2>
4+
</div>
5+
</template>
6+
7+
<script>
8+
9+
export default {
10+
props: {
11+
name: {
12+
type: String,
13+
default: 'Vue!'
14+
}
15+
}
16+
}
17+
</script>

examples/route-props/app.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import Vue from 'vue'
2+
import VueRouter from 'vue-router'
3+
import Hello from './Hello.vue'
4+
5+
Vue.use(VueRouter)
6+
7+
function dynamicPropsFn (route) {
8+
const now = new Date()
9+
return {
10+
name: (now.getFullYear() + parseInt(route.params.years)) + '!'
11+
}
12+
}
13+
14+
const router = new VueRouter({
15+
mode: 'history',
16+
base: __dirname,
17+
routes: [
18+
{ path: '/', component: Hello }, // No props, no nothing
19+
{ path: '/hello/:name', component: Hello, props: true }, // Pass route.params to props
20+
{ path: '/static', component: Hello, props: { name: 'world' }}, // static values
21+
{ path: '/dynamic/:years', component: Hello, props: dynamicPropsFn } // custom logic for mapping between route and props
22+
]
23+
})
24+
25+
new Vue({
26+
router,
27+
template: `
28+
<div id="app">
29+
<h1>Route props</h1>
30+
<ul>
31+
<li><router-link to="/">/</router-link></li>
32+
<li><router-link to="/hello/you">/hello/you</router-link></li>
33+
<li><router-link to="/static">/static</router-link></li>
34+
<li><router-link to="/dynamic/1">/dynamic/1</router-link></li>
35+
</ul>
36+
<router-view class="view"></router-view>
37+
</div>
38+
`
39+
}).$mount('#app')

examples/route-props/index.html

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!DOCTYPE html>
2+
<link rel="stylesheet" href="/global.css">
3+
<a href="/">&larr; Examples index</a>
4+
<div id="app"></div>
5+
<script src="/__build__/shared.js"></script>
6+
<script src="/__build__/route-props.js"></script>

src/components/view.js

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { resolveProps } from '../util/props'
2+
13
export default {
24
name: 'router-view',
35
functional: true,
@@ -56,6 +58,7 @@ export default {
5658
matched.instances[name] = undefined
5759
}
5860
}
61+
data.props = resolveProps(route, component, matched.props && matched.props[name])
5962

6063
return h(component, data, children)
6164
}

src/create-route-map.js

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ function addRouteRecord (
4444
name,
4545
parent,
4646
matchAs,
47+
props: typeof route.props === 'undefined' ? {} : (route.components ? route.props : { default: route.props }),
4748
redirect: route.redirect,
4849
beforeEnter: route.beforeEnter,
4950
meta: route.meta || {}

src/util/props.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
import { warn } from './warn'
3+
4+
export function resolveProps (route, component, config) {
5+
switch (typeof config) {
6+
7+
case 'undefined':
8+
return
9+
10+
case 'object':
11+
return config
12+
13+
case 'function':
14+
return config(route)
15+
16+
case 'boolean':
17+
if (!config) {
18+
return
19+
}
20+
return route.params
21+
22+
default:
23+
warn(false, `props in "${route.path}" is a ${typeof config}, expecting an object, function or boolean.`)
24+
}
25+
}
26+

test/e2e/nightwatch.config.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// http://nightwatchjs.org/guide#settings-file
2+
23
module.exports = {
34
'src_folders': ['test/e2e/specs'],
45
'output_folder': 'test/e2e/reports',
@@ -7,7 +8,7 @@ module.exports = {
78

89
'selenium': {
910
'start_process': true,
10-
'server_path': 'node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.1.jar',
11+
'server_path': require('selenium-server').path,
1112
'host': '127.0.0.1',
1213
'port': 4444,
1314
'cli_args': {

test/e2e/specs/route-props.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
module.exports = {
2+
'route-props': function (browser) {
3+
browser
4+
.url('http://localhost:8080/route-props/')
5+
.waitForElementVisible('#app', 1000)
6+
.assert.count('li a', 4)
7+
8+
.assert.urlEquals('http://localhost:8080/route-props/')
9+
.assert.containsText('.hello', 'Hello Vue!')
10+
11+
.click('li:nth-child(2) a')
12+
.assert.urlEquals('http://localhost:8080/route-props/hello/you')
13+
.assert.containsText('.hello', 'Hello you')
14+
15+
.click('li:nth-child(3) a')
16+
.assert.urlEquals('http://localhost:8080/route-props/static')
17+
.assert.containsText('.hello', 'Hello world')
18+
19+
.click('li:nth-child(4) a')
20+
.assert.urlEquals('http://localhost:8080/route-props/dynamic/1')
21+
.assert.containsText('.hello', 'Hello ' + ((new Date()).getFullYear() + 1)+ '!')
22+
23+
.end()
24+
}
25+
}

0 commit comments

Comments
 (0)