(1)安装
npm install vue-router
(2)构建文件目录
在src目录下创建一个router文件夹,然后创建一个index.js
(3)这里我们通过模块化的方式进行创建路由,方便代码的管理,这里只是对路插件进行了注册,然后创建好路由对象。通过export default 关键字将创建好的路由对象暴露出去。
//index.js
import VueRouter from 'vue-router'
import Vue from 'vue'
import Home from "../views/Home";
Vue.use(VueRouter)//注册路由插件
export default new VueRouter({
routes:[{
path:'/',
component:Home
}]
})
(4)在入口文件main.js引入创建好的路由对象,并且把他挂载到Vue实例中。
//main.js
import Vue from 'vue'
import App from './App.vue'
import store from '@/store'
import router from '@/router'//这里就是引入了我们创建好的路由对象。模块化的编程思维
Vue.config.productionTip = false
Vue.prototype.bus = new Vue()
new Vue({
store,
router,
render: h => h(App),
}).$mount('#app')
可以理解成,通过标签进行跳转
声明式导航:
定义路由规则
{
path:'/',
component:Home
name:home
}
(1)router-link导航标签to属性使用字符串方式
<router-link to="/">go to home</router-link>
(2)router-link导航标签to使用对象的方式
<router-link :to="{path:'/'}">go to home</router-link>
<router-link :to="{name:'home'}">go to home</router-link>
可以理解成JS进行跳转
编程式导航:router.push(...)
下面的例子包含了动态路由匹配和query查询参数的知识,不清楚的可以先看了这两者的内容再回来看此处的内容。
// 字符串
router.push('home')
// 对象
router.push({
path: 'home' })
// 命名的路由
router.push({
name: 'user', params: {
userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({
path: 'register', query: {
plan: 'private' }})
注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 与params配合或手写完整的带有参数的 path:
const userId = '123'
router.push({
name: 'user', params: {
userId }}) // -> /user/123
router.push({
path: `/user/${
userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({
path: '/user', params: {
userId }}) // -> /user
定义路由规则
{
path:'/user/:id',
component:User
name:user
}
<router-link to="/user/01">go to home</router-link>
<router-link :to="{path:'/user/01'}">go to home</router-link>
<router-link :to="{name:'/user',params={id:'01'}}">go to home</router-link>
通过如上的方式进行定义,可以通过$route.params.id 获动态路由参数:id值为’01‘
注意:
当使用对象的方式进行匹配时候,不能通过path和params的方式。只能通过name和params的方式
如下方式,不能匹配到路由规则{path:'/user/:id'}
,如下表述只能被理解成’/user’,
即使通过*通配符匹配到该路由,params也不会被传递过去,因为要有path这个属性就不会去解析params的属性了。
<router-link :to="{path:'/user',params={id:'01'}}">go to home</router-link>
我们通常使用*捕获其他意外的路径,进行个兜底的处理,通常将其导航到404错误页面。
{
// 会匹配所有路径
path: '*'
}
{
// 会匹配以 `/user-` 开头的任意路径
path: '/user-*'
}
当使用一个通配符时,$route.params 内会自动添加一个名为 pathMatch 参数。它包含了 URL 通过通配符被匹配的部分
<router-link to=“/user?name=zhangsan">...</router-link>
<router-link :to="{path:'/user?zhangsan'}">...</router-link>
<router-link :to="{path:'/user',query:{name:'zhangsan'}}">...</router-link>
<router-link :to="{name:'user',query:{name:'zhangsan'}}">...</router-link>
查询参数不想动态路由参数匹配那样,就算使用了path,依然可以使用query进行传参;
以上query传递过来的参数可以通过this.$route.query.name
进行获取。
如果路由从/user/01
导航到/user/02
,原来的组件实例会被复用。因为有两个路由都渲染同一个组件,这意味着组件的生命周期钩子不会被再次调用。因此需要通过其他方式进行监听参数的变化来做出响应。
(1)通过watch进行监听
const User = {
template: '...',
watch: {
$route(to, from) {
// 对路由变化作出响应...
}
}
}
(2)通过导航守卫进行监听
const User = {
template: '...',
beforeRouteUpdate(to, from, next) {
// react to route changes...
// don't forget to call next()
}
}
特别地我把这三者的概念放在一起来阐述,是为了更好的去区分他们之间的区别。这些内容都是在路由规则去配置的
。
{
path: '/pageOne',
component:PageOne,
alias:"/firstPage",
name:"pageOne",
redirect:{
name:'pageTwo'}
},
{
path: '/pageTwo',
component:PageTwo,
name:'pageTwo'
}
(1)命名路由:可以理解成给这个路由取个名字
即使通过name属性给路由取一个名字
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
(2)路由别名:可以理解成这个路由的第二个名字。
例如:/a
的别名是/b
,当用户访问/b的时候,URL会保持/b但是路由匹配到的内容则为/a,也就是知识URL内容显示/b
内容实则是/a
注意了:这里别名要使用路径的方式去表述,而不是跟命名路由那样直接写名字哦~
const router = new VueRouter({
routes: [
{
path: '/a', component: A, alias: '/b' }
]
})
(3)重定向:可以理解为访问/a
的时候直接跳转到/b
重定向的表述有三种形式:
const router = new VueRouter({
routes: [
{
path: '/a', redirect: '/b' }
]
})
const router = new VueRouter({
routes: [
{
path: '/a', redirect: {
name: 'foo' }}
]
})
const router = new VueRouter({
routes: [
{
path: '/a', redirect: to => {
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}}
]
})
嵌套路由可以这么理解,所匹配的路由渲染出来的组件中包含路由组件,’/user’当我们匹配到一个路由渲染出一个组件User,但是如果想继续在User组件的
继续匹配。则我们要通过/user/childRouteName
进一步匹配。"childRouteName"就是我们路由规则children中对应的path的值啦。
{
path: '/user',
component: User,
children: [
{
// 当 /user//profile 匹配成功,
// UserProfile 会被渲染在 User 的 中
path: 'profile',
component: UserProfile
},
{
// 当 /user//posts 匹配成功
// UserPosts 会被渲染在 User 的 中
path: 'posts',
component: UserPosts
}
]
}
APP.Vue中
<div id="app">
<router-view></router-view>
</div>
User组件中
const User = {
template: `
User组件
`
}
注意:
定义了嵌套路由,即定义了children的情况下,必须是完整的路由才可以匹配正确。也就是 当 /user/profile
匹配成功,但是/user
这样是无法匹配成功的。
当一个组件上同时渲染多个视图,注意是同级展示多个视图,而不是嵌套展示。那此时就可以通过命名视图来解决这个问题。
路由规则定义
{
path:"/namingRoute",
components:{
//注意此处components是带's'结尾的,之前单个的时候是不带的。
default:Home,
one:PageOne,
two:PageTwo
}
}
组件定义
<router-view></router-view>//渲染default对应的组件
<router-view name="one"></router-view>//渲染one对应的组件
<router-view name="two"></router-view>//渲染two对应的组件
当URL为:/namingRoute
的时候 匹配到该路由,则会按照对应的router-view视图组件进行渲染。
可以理解成通过全局router实例对象router进行定义的守卫。
使用方式:
beforeEach((to,from,next)=>{
//...
})
在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
使用方式:
router.beforeResolve((to, from, next) => {
// ...
})
钩子不会接受 next 函数也不会改变导航本身:
使用方式:
router.afterEach((to, from) => {
// ...
})
使用的位置:通常在router文件夹下的index.js
const router = new VueRouter({ ... })
//全局前置守卫
router.beforeEach((to, from, next) => {
// ...
})
//全局解析守卫
router.beforeResolve((to, from, next) => {
// ...
})
//全局后置钩子
router.afterEach((to, from) => {
// ...
})
可以理解成在路由规则上定义的守卫
可以理解成在组件内定义的守卫
const User = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
}
}
注意:
该守卫不能直接使用this
访问vue实例对象,因为此时组件实例还没有被创建。但是可以通过给next方法传递回调来方位组件的实例。
给next()传递回调,仅在beforeRouteEnter使用有效!!!
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
})
}
const User = {
template: `...`,
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
}
}
const User = {
template: `...`,
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
正常首次访问路由的执行顺序
next
的回调函数。并且把创建号的组件实例作为回调函数的参数传入。