目录
一、安装路由
二、在项目中引入
三、使用路由
四、路由组件传参
1、动态路由
2、props路由组件传参
五、嵌套路由配置
六、别名
七、History模式
八、编程式导航
1、不带参数
2、带参数(params和query)
九、路由导航守卫
1、全局前置守卫
2、全局后置钩子
3、路由独享守卫
4、组件内的守卫(3个)
5、路由元信息
在vue中,对页面的管理用到的是路由(vue-router)
路由作用:完成页面的跳转,来管理页面
在项目中安装路由可以通过vue脚手架安装,也可以手动进行安装配置,这里展示的是手动安装
npm install --save vue-router
1、在src目录下,创建router文件夹,里面写入路由相关的配置
// 引入vue
import Vue from 'vue'
// 引入路由
import VueRouter from 'vue-router'
// 引入需要跳转的页面
import Home from '@/views/Home.vue'
// 通过.use()方法使用路由
Vue.use(VueRouter)
// routes:对页面的管理(通过数组中套对象的形式)
const routes = [
{
// 跳转的路径
path: '/home',
// 路由组件的名字
name: 'Home',
// 跳转的组件
component: Home
},
{
path: '/about',
name: 'About',
// 异步加载
component: () => import('@/views/About.vue')
}
]
const router = new VueRouter({
routes
})
export default router
2、在main.js入口文件中引入router,并挂载到vue原型上
import Vue from 'vue'
import App from './App.vue'
// 引入配置的路由文件
import router from './router'
Vue.config.productionTip = false
// 挂载
new Vue({
router,
render: h => h(App)
}).$mount('#app')
1、
只配置完路由信息后,在地址栏输入需要跳转的路径,页面是跳转不过去的,需要在组件中写上路由的出口:
2、
router-link标签和a标签的作用是一样的,用于页面跳转,to属性写的是需要跳转的路径
路由组件传参分两种:动态路由和props
在页面跳转中,是可以携带参数的
在router目录下的index.js中的路径参数要写成动态的
const routers = [
{
// 动态路径参数,以冒号开头
path: '/home/:name/:id',
name: 'home',
component: () => import('./xxx')
}
]
组件中的router-link的to属性变成动态属性 里面写成对象
有两个参数: :to="{name + params}"
参数1:name是路由组件的名字
参数2:params是传递的参数
例如:
User
路由组件传参,在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 url 上使用,限制了灵活性,使用props将组件和路由解耦。
使用props解耦的目的:不要在组件里出现路由的参数
在路由配置中使用props有两种方法
方法1:
const routes = [
{
path: '/user/:id',
component: User,
// 允许在User组件通过props传参
props: true
}
]
方法2: 函数方式
const routers = [
{
path: '/user/:id',
component: User,
props: route => ({id: route.params.id})
}
]
在组件中用props写入需要传递的参数
export default {
props: ['id', 'name']
}
一个路由组件中可能有二级,三级子路由,如果要进行跳转,也需要对子路由进行配置。
在对子路由的配置中经常用到redirect重定向:在父级添加,路由组件的默认显示路径。
const routes = [
{
path: "/about",
name: "about",
component: () => import("../views/AboutView.vue"),
// 重定向 /about/us为默认路径
redirect: "/about/us",
// children子级(子路由)
children: [
{
// 二级导航的路径不要加 /
path: "us",
// name可以不写
component: () => import("../views/AboutSub/AboutUS.vue")
},
{
path: "info",
component: () => import("../views/AboutSub/AboutInfo.vue")
}
]
}
]
别名的意思是:/a的别名是/b, 也就是说, 当用户访问/b时, url会保持为/b, 但是路由匹配则是/a, 就像用户访问/a一样(组件没变,但地址变了)
用途:多个功能共享一个组件。给用户感觉跳转到新界面了,但其实还是同一个组件。
const router = new VueRouter({
routes: [
{
path: '/about',
component: About,
// 访问/b显示的是About组件
alias: '/b'
}
]
})
Hash模式: 路径带井号 #
History模式:路径不带 #
语法配置:
const router = new VueRouter({
mode: 'history',
routes
})
在上面的
所谓的编程式导航,就是通过js来控制跳转,借助router的实例方法: router.push()。在vue实例内部, 可以通过 $router 访问路由实例。因此可以调用 this.$router.push。
$route:一般获取路由信息(路径,query,params)
$router:一般进行编程式导航进行路由跳转(push|replace) push与replace的区别在于能否记录历史记录
编程式导航的路由跳转也分了带参和不带参
// 字符串
this.$router.push('/home')
// 对象
this.$router.push({ path: '/home' })
携带的参数分为params参数和query参数
(1)params参数:属于路径当中的一部分,需要注意:在配置路由的时候,需要占位
写法(/abc):/search/abc
注意:命名的路由跳转,传参 name只能和params搭配使用;path不能和params一起使用
this.$router.push({
name: 'user', // 要跳转的组件名
// 都是跳转到user页面,params只是路径地址后面的参数不同
params: {
// 参数需要在路由配置的路径中进行占位
uname: 'admin',
id:123
}
})
// path路径跳转 拼接path路径
this.$router.push({
path: '/user/admin/123'
})
(2)query参数:不属于路径当中的一部分,类似于ajax中的queryString ?号的部分
写法(?k=v&kv=):/search?k=v&kv=,不需要占位
// 第一种:字符串形式
this.$router.push('/search/'+this.keyword+'?k='+this.keyword.toUpperCase());
// 第二种:模版字符串
this.$router.push(`/search/${this.keyword}?k=${this.keyword.toUpperCase()}`);
query参数也可以写成对象的形式,例如
this.$router.push({ path: '/about', query: { plan: 'private' } })
最后的路径会变成:/register?plan=private
问:路由传递参数(对象写法)path是否可以结合params参数一起使用?
this.$router.push({
path: 'search',
params: {keyword: this.keyword},
query: {k:this.keyword.toUpperCase()}
})答:路由跳转传参的时候,对象的写法可以是name、path形式,但需要注意的是,path这种写法不能与params参数一起使用
路由守卫作用:拦截作用
1、全局前置守卫
2、全局后置钩子
3、路由独享守卫
4、组件内的守卫
5、路由元信息
使用router.beforeEach() 注册一个全局前置守卫,回调里有三个参数
参数1 to:Route: 即将要进入的目标 路由对象
参数2 from: Route: 当前导航正要离开的路由
参数3 next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖next方法的调用参数。next是放行, 一定要有。
注意:只要发生路由跳转,都会被拦截,都会走全局前置守卫
// 在router目录下index.js中
router.beforeEach((to,from,next) => {
// 对参数1,2进行打印
console.log(to);
console.log(from);
// 一定要有next放行
next();
})
可以看到to,from打印的结果:里面包含了路径,路由名字,参数等
1.next(): 进行管道中的下一个钩子。如果全部钩子执行完了, 则导航的状态就confirmed(确认的)。
2.next(false): 中断当前的导航。如果浏览器的url改变了(可能是用户手动或浏览器后退按钮),
那么url地址会重置到from路由对应的地址。
3.next('/')或next({ path:'/' }): 跳转的一个指定的页面。
4.next(error):如果传入next的参数是一个Error实例, 则导航会被终止且该错误会被传递给router.onError()注册过的回调。
例:如果当前不是登录页,就跳转到登录页
router.beforeEach((to, from, next) => {
// 如果不是Login页面就让它跳转到Login;如果已经是Login页面,就放行
if (to.name !== 'Login') next({ name:'Login' })
else next()
})
可以注册全局后置钩子,和守卫不同的是,这些钩子不会接受 next 函数,也不会改变导航本身
router.afterEach((to, from) => {
...
})
可以在路由配置上直接定义 beforeEnter 守卫
路由独享守卫和全局前置守卫不一样的是:独享守卫只作用于自己的单个路由组件,而全局前置守卫是对所有路由组件生效。
const routes = [
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue'),
beforeEnter: (to, from, next) => {
console.log('路由独享守卫');
next()
}
}
]
组件内的守卫:beforeRouteEnter(读不到this),beforeRouteUpdate,beforeRouteLeave
export default {
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// !!! 不能获取组件实例 'this'
// 因为当守卫执行前,组件实例还没被创建
},
// !!!很重要!!!
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例:对于一个带有动态参数的路径 /foo/:id, 在 /foo/1 和 /foo/2 之间跳转的时候
// 由于会渲染同样的Foo组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 'this'
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 'this'
}
}
路由元信息:定义路由的时候可以配置 mata 字段,标记作用。
例如:一个有网站的首页,订单页,个人中心页面,只有首页不需要登录就能访问,其他页面均需要登录后访问,这时候就需要在配置路由的时候,用meta个需要登录的页面打上标记。
const routes = [
{
path: '/',
name: 'home',
component: HomeView,
meta: {
// isLogin为false,不需要登录
isLogin: false
}
},
{
path: '/order',
name: 'order',
component: () => import('../views/AboutView.vue'),
meta: {
// 为true,则需要登录
isLogin: true
}
},
{
path: '/center',
name: 'center',
component: () => import('../views/CenterView.vue'),
meta: {
isLogin: true
}
},
{
path: '/login',
name: 'Login',
component: () => import('../views/Login.vue')
}
]
下面是全局前置守卫的配置:
router.beforeEach((to, from, next) => {
// 如果meta的isLogin字段为true,则必须要登录才能进入
if (to.meta.isLogin) {
// 再判断用户是否登录
let user = '' // 判断用户是否有登录信息
// 已登录,放行
if (user) {
next()
}
// 未登录,到登录页
else {
next('/login')
}
}
// 不需要登录的页面,直接放行
else {
next()
}
})