在组件中使用
$route会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。
1. 使用 props 将组件和路由解耦:
取代与 $route 的耦合
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
routes: [{ path: '/user/:id', component: User }]
})
通过 props 解耦
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true },
// 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
<!DOCTYPE html>
<html>
<head>
<title>vue-router</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.8/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@3.1.3/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<router-link to="/user/lxl">default</router-link>
<router-link to="/user/long">sidebar</router-link>
<router-view></router-view>
<router-view name="sidebar"></router-view>
</div>
<script>
const Sidebar = {
template: `<div class="Sidebar">
<h2>Sidebar {{ id }}</h2>
</div>`
};
const User = {
props: ["id"],
template: "<div>User {{ id }}</div>"
};
const router = new VueRouter({
routes: [
// { path: "/user/:id", component: User, props: true },
// 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
{
path: "/user/:id",
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
});
const app = new Vue({
router,
el: "#app"
}).$mount("#app");
</script>
</body>
</html>
这样就可以在任何地方使用该组件,使得该组件更易于重用和测试
2. props设置为布尔值
如果 props 被设置为 true,route.params 将会被设置为组件的props属性。
3. props设置为对象
如果 props 是一个对象,它会被按原样设置为组件的props属性。当 props 是静态的时候有用。
const Promotion = {
props: ["newsletterPopup"],
template: `<div class="Promotion">
<h2>Promotion {{ newsletterPopup }}</h2>
</div>`
};
const router = new VueRouter({
routes: [
{
path: '/promotion/from-newsletter',
component: Promotion,
props: { newsletterPopup: false }
}
]
})
4. props设置为函数
可以创建一个函数返回 props。这样便可以将参数转换成另一种类型,将静态值与基于路由的值结合等等。
const router = new VueRouter({
routes: [
{
path: '/search',
component: SearchUser,
props: route => ({ query: route.query.q })
}
]
})
URL /search?q=vue 会将 {query: 'vue'} 作为组件的props属性传递给 SearchUser 组件。
<!DOCTYPE html>
<html>
<head>
<title>vue-router</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.8/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@3.1.3/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<router-link to="/search?q=vue">search</router-link>
<router-view></router-view>
</div>
<script>
const SearchUser = {
props: ["queryQ"],
template: `<div class="SearchUser">
<h2>SearchUser {{ queryQ }}</h2>
</div>`
};
const router = new VueRouter({
routes: [
{
path: "/search",
component: SearchUser,
props: route => ({ queryQ: route.query.q })
}
]
});
const app = new Vue({
router,
el: "#app"
}).$mount("#app");
</script>
</body>
</html>
请尽可能保持 props 函数为无状态的,因为它只会在路由发生变化时起作用。如果你需要状态来定义 props,请使用包装组件,这样 Vue 才可以对状态变化做出反应。
5. 例子
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.8/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@3.1.3/dist/vue-router.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const Hello = {
props: ["name"],
template: `<div class="Hello">
<h2>Hello {{ name }}</h2>
</div>`
};
function dynamicPropsFn(route) {
const now = new Date();
return {
name: now.getFullYear() + parseInt(route.params.years) + "!"
};
}
const router = new VueRouter({
mode: "history",
// base: __dirname,
routes: [
{ path: "/", component: Hello }, // No props, no nothing
{ path: "/hello/:name", component: Hello, props: true }, // Pass route.params to props
{ path: "/static", component: Hello, props: { name: "world" } }, // static values
{ path: "/dynamic/:years", component: Hello, props: dynamicPropsFn }, // custom logic for mapping between route and props
{ path: "/attrs", component: Hello, props: { name: "attrs" } }
]
});
new Vue({
router,
template: `
<div id="app">
<h1>Route props</h1>
<ul>
<li><router-link to="/">/</router-link></li>
<li><router-link to="/hello/you">/hello/you</router-link></li>
<li><router-link to="/static">/static</router-link></li>
<li><router-link to="/dynamic/1">/dynamic/1</router-link></li>
<li><router-link to="/attrs">/attrs</router-link></li>
</ul>
<router-view class="view" foo="123"></router-view>
</div>
`
}).$mount("#app");
</script>
</html>