Vue Router
Vue Router 是 Vue.js 官方的路由管理器。用 Vue.js + Vue Router 创建单页应用。
SPA的理解
-
单页Web应用(single page web application,SPA)
-
整个应用只有一个完整的页面,页面变化都是在这一个页面更新的
-
点击链接时, 不会刷新整个页面,只会做页面的局部更新,也会更新浏览历史(地址)
-
点击链接也不会向服务器发请求,数据都需要通过ajax发送请求, 并在前端异步展现
简述前端路由的原理
- 点击链接不会刷新整个页面 --> 给 a 标签绑定点击事件,阻止其默认行为
- 会更新浏览历史(地址) --> 调用 history.push(path),就可以更新了
- 会局部更新 --> 内部会监听浏览历史的变化(history.listen(listener)),一旦发生变化就会遍历路由的所有配置,看当前路径(浏览地址)是否匹配上路由路径(path),匹配上就加载 component
使用
使用 Vue.js ,可以通过组合组件来组成应用程序,当把 Vue Router 添加进来,需要做的是,将组件 (components) 映射到路由 (routes),然后告诉 Vue Router 在哪里渲染它们。
用路由的3步
-
定义路由组件
-
注册路由
-
使用路由
<router-link>
用来路由链接导航
<router-view>
用来显示当前路由组件
安装 路由插件
npm i vue-router
当安装插件之后, 就会全局注册两个组件:router-link,router-view,还会给原型上添加一些属性
1.定义路由组件
在src下创建一个文件router,在创建一个文件夹来定义路由
Vue.use(VueRouter);
// 创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
// 定义路由配置
routes: [
{
path: "/home", // 路由路径
component: Home, // 路由组件
// 子路由
children: [
{
path: "/home/message", // 完整写法
component: Message,
children: [
{
name:"Detail",// 加上name属性,就叫做命名路由
path: "detail/:id",// 动态路由配置,能匹配多个路径
// path: "detail/:id?", // ? 表示params 参数是可选的
component: Detail,
props(route) {
return {
...route.params,
...route.query
}
}
}
]
},
{
path: "news", // 简写
component: News
}
]
},
{
path: "/about",
component: About
},
{
// 当路径是/时,会切换到/home
path: "/",
redirect: "/home" //重定向
}
]
})
export default router;
2.注册路由
new Vue({
render: h => h(App),
router, // 应用路由器
}).$mount('#app')
3.使用路由
<ul class="nav nav-pills nav-stacked">
<!--
router-link 路由连接导航
- 切换地址
- 当你点击选中 router-link 时,会添加两个类名:router-link-exact-active router-link-active
- active-class 可以修改类名 router-link-active(active-class:默认是router-link-active)
router-view 显示对应的路由组件
- 内部会根据当前的地址,遍历路由中的routes配置,找到相对应的路由组件进行显示
-->
<li>
<router-link to="/about" active-class="active">About</router-link>
</li>
<li>
<router-link to="/home">Home</router-link>
</li>
</ul>
<!-- 显示对应的路由组件 -->
<router-view></router-view>
路由传参的方式
<!--
路由传参的方式:
1. params参数
(1)路由配置:
{
path: '/xxx/:id', // :id 动态路由匹配,能匹配多个地址
component: Xxx
}
跳转路由路径
<router-link to="/xxx/1">xxx</router-link>
子路由接受 :id 的参数
this.$route.params.id
当 :id 的参数发生变化时,需要使用watch监视属性的变化,来更新数据
watch: {
$route: {
handler(newVal) {
const id = +newVal.params.id;
this.message = this.messages.find((message) => message.id === id);
},
// 正常情况下,watch只有值发生变化的时候才会调用
// 一上来会调用一次
immediate: true,
},
},
(2)路由配置
{
name: "Search",
// ? 表示params 参数是可选的
path: "/search/:searchText?",
component: Search,
}
this.$router.push({ name: '必须使用命名路由', params: {} })
可选参数:需要 params 就加上 params 选项,不需要 params 就去掉
2. query
路由链接设置
<router-link to="/xxx?name=jack&age=18">xxx</router-link>
子组件获取
this.$route.query
3. props
将原先的params参数和query参数以props方式传递给组件
子组件配置
props(route) {
return {
...route.params,
...route.query,
};
},
子组件声明接受
props: ['id', 'name', 'age']
子组件使用
this.xxx
4. 命名路由
- 路由取个名字
{
name: "Detail", // 命名路由
path: "detail/:id",
component: Detail,
}
- 路由路径
<router-link
:to="{
name: 'Detail', // 跳转哪个命名路由
params: {
id: message.id,
},
query: {
name: 'jack',
age: 18,
},
}"
>xxx</router-link>
5. 给相同层级的路由组件一起传递公共参数
传参
<router-view key="value"></router-view>
路由组件声明接受
props: ['key']
路由组件使用
this.xxx
6. meta
路由配置
meta: { key: value } // 当这个组件加载显示时,meta中的参数会传到$route中,组件中的meta只属于当前组件,(可以用在控制组件的显示隐藏)
使用 meta 参数
this.$route.meta.xxx
-->
<ul>
<li v-for="message in messages" :key="message.id">
<!-- <router-link :to="`/home/message/detail/${message.id}?name=suzy&age=25`">{{message.content}}</router-link> -->
<router-link
:to="{
name: 'Detail', // 跳转哪个命名路由
params:{
id:message.id,
},
query:{
name:'jack',
age:18,
}
}"
>{{ message.content }}</router-link>
</li>
</ul>
<router-view suzy="iu"></router-view>
动态路由匹配
const User = {
template: '<div>User</div>'
}
const router = new VueRouter({
routes: [
// 动态路径参数 以冒号开头
{ path: '/user/:id', component: User }
]
})
一个“路径参数”使用冒号 :
标记。当匹配到一个路由时,参数值会被设置到 this.$route.params
,可以在每个组件内使用。于是,我们可以更新 User
的模板,输出当前用户的 ID:
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
嵌套路由
需要在 VueRouter
的参数中使用 children
配置
Vue.use(VueRouter);
// 创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
// 定义路由配置
routes: [
{
path: "/home", // 路由路径
component: Home, // 路由组件
// 子路由
children: [
{
path: "/home/message", // 完整写法
component: Message,
children: [
{
name:"Detail",// 加上name属性,就叫做命名路由
path: "detail/:id",
component: Detail,
props(route) {
return {
...route.params,
...route.query
}
}
}
]
},
]
},
]
})
命名路由
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',// 加上name属性,就叫做命名路由
component: User
}
]
})
要链接到一个命名路由,可以给 router-link
的 to
属性传一个对象:
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
这跟代码调用 router.push()
是一回事:
router.push({ name: 'user', params: { userId: 123 }})
这两种方式都会把路由导航到 /user/123
路径。
命名视图
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口,如果 router-view
没有设置名字,那么默认为 default
。
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components
配置 (带上 s):
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: Foo,
a: Bar,
b: Baz
}
}
]
})
重定向
重定向也是通过 routes
配置来完成
const router = new VueRouter({
// 定义路由配置
routes: [
{
path: "/home", // 路由路径
component: Home, // 路由组件
// 子路由
}
{
// 当路径是/时,会切换到/home
path: "/",
redirect: "/home" //重定向
}
]
})
编程式导航
-
this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
-
this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
-
this.$router.back(): 请求(返回)上一个记录路由
4)this.$router.forward():请求(返回)下一个记录路由
-
this.$router.go(-1): 请求(返回)上一个记录路由
-
this.$router.go(1): 请求下一个记录路由
/*
$route
用来获取路由参数(params、query)和路由路径(path)
$router
用来编程式导航(push、replace、go、back、forward)
两种路由跳转的方式:
1. 路由链接导航
router-link
2. 编程式导航
this.$router.push/replace()
如果点击链接或者按钮只需要进行路由跳转,那么就用第一种方式
例子:导航链接
如果点击链接或者按钮需要做一些其他事,再进行路由跳转,那么就用第二种方式
例子:登录按钮、修改按钮
*/
例如
methods: {
push(id) {
// 编程式导航
//console.log(this);
this.$router.push(`/home/message/detail/${id}?name=suzy&age=25`);
},
replace(id) {
this.$router.replace(`/home/message/detail/${id}?name=suzy&age=25`);
}
}
<button @click="push(message.id)">push</button>
<button @click="replace(message.id)">replace</button>
<button @click="$router.back()">goBack</button>
<button @click="$router.forward()">goFoward</button>
缓存路由组件
-
默认情况下, 被切换的路由组件对象会死亡释放, 再次回来时是重新创建的
-
如果可以缓存路由组件对象, 可以提高用户体验
<keep-alive>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
<keep-alive include="Home,About">
<!-- exclude="Home" 缓存排除Home -->
<!-- <keep-alive exclude="Home"> -->
<router-view></router-view>
</keep-alive>
当组件在 <keep-alive>
内被切换,它的 activated
和 deactivated
这两个生命周期钩子函数将会被对应执行。只有使用 <keep-alive>
才会有这两个钩子函数。如果需要使用<keep-alive>
的组件,及时更新数据需要在两个钩子函数中操作
activated
:被 keep-alive 缓存的组件激活时调用。
deactivated
:被 keep-alive 缓存的组件停用时调用。
跳转路由链接的方式
-
路由链接导航 router-link
-
编程式导航 this.$router.push/replace/back/forward/go()
-
用法区别:
- 如果只需要跳转链接,用路由链接导航
- 如果需要先做一些其他事(发送请求等),再跳转链接,用编程式导航