vue-router
1.安装 vue-router
npm install --save vue-router
2.使用 vue-router
// 1、先引入 vue 和 vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'
import Page1 from '../views/page1.vue'
// 2、使用VueRouter插件
Vue.use(VueRouter)
// 3、配置路由规则 [{},{},{}]
const routes = [
{
path: '/page1',
component: Page1
}
]
// 4、实例化路由器对象,并且使用上面routes规则
const router = new VueRouter({
routes
})
// 5、将第四步的router暴露出去
export default router
- 在 new Vue 实例的地方引入暴露出来的 router 实例对象配置给跟组件的 router 选项
- 项目中选择某个位置放入一个 router-view 这个组件 ( 路由视图 ,和slot用法差不多)
router-link 和 a 标签的区别
1、默认情况下,router-link 的 to 属性不需要加 # 号,a标签需要。
2、router-link 可以帮我们实现高亮的效果,通过 class为router-link-active设置样式。router-link-active类名是可以修改的,在router-link标签上设置active-class修改。
动态路由匹配
{
// 通过 :来指定后面的id是动态路由参数
path: '/detail/:id/:name',
component: Detail
}
当我们使用上路由之后,会在 Vue 的原型上挂载 两个属性
- ==route可以获取到当前路由对象信息,里面的 params 有传递的动态参数,query是url地址后面?传递的。
- ==$router== 路由器的实例对象,里面有一些方法
嵌套路由
要在嵌套的出口中渲染组件,需要在 VueRouter 的参数中使用 children 配置:
const routes = [
{
path: '/home',
component: Home,
children: [
{
// url地址: /home/page1
path: 'page1',
component: Page1
},
{
path: 'page2',
component: Page2
}
]
}
]
要注意,以 / 开头的嵌套路径会被当作根路径。设置的嵌套路由就无效了。
编程式导航 - 通过js代码来控制路由的跳转
- $router.push() 跳转页面,新增一个历史记录
- $router.back() 后退
- $router.forward() 前进
- $router.go() 根据参数来看是前进还是后退
- $router.replace() 重定向页面,不加历史记录
router-link标签也可以加上replace属性,使其重定向页面,没有历史记录
命令路由
在路由规则上给每个规则加上name属性,后续方便我们操作路由的跳转。一般不会给有子集路由的起名字,只给其子路由命名。
<router-link to="/home/page1"></router-link>
<router-link :to="{ path: '/home/page1', name: 'page1', query: {}, params: {} }"></router-link>
to属性传对象的时候,可以有如果属性
- path 路由路径
- name 命名路由的名字
- query search参数,url ?后面的参数
- params 动态路由匹配参数
PS: params 与 path 不能共存,如果你要传递 params,那么不要使用 path。path是url地址,params是url地址后面/传递过去的,所以有冲突,会以path为主。
命名视图
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s)
重定向和别名
重定向: redirect
“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b
{
// 当url地址都没有匹配到上面的规则的时候,就会匹配*,让url重定向到了 /home/page1
path: '*',
redirect: '/home/page1'
}
{
// 加上这个之后,访问localhost:8080/home 会自动重定向到 /home/page1
path: '',
redirect: '/home/page1'
}
别名:alias
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
{
name: 'login',
alias: '/haha', // 定义了一个别名,当地址为haha也能跳转到login页面
path: '/login',
component: Login
}
路由组件传参
有三种方法:
1、布尔模式,设置props属性为true
{
// 通过 :来指定后面的id是动态路由参数
name: 'detail',
path: '/detail/:id/:name',
component: Detail,
// 设置props为true,在Detial组件中就可以使用 props
// 来定义id与name,并且使用props接收并使用id和name,
// 就不需要使用this.$route.params.id 获取了。
props: true
}
2、对象模式
props: { id :1, name : '苹果' }
props传一个对象过去,也可以接收到数据。
3、函数模式
props: (route) => {
return {
id : route.params.id,
name : route.params.name
}
}
vue 路由的两种模式
- hash (默认),带#号
- history 不带#号
要修改当前路由模式可以在 实例化 路由器对象的时候设置 mode 选项
new VueRouter({
mode: 'history'
})
这两种模式的区别
- 从外观上来说,hash模式会在url地址上面有一个 # 号,而 history 没有,更像url地址。
- 从原理上来说,hash模式是通过 window.onHashChagne 这个事件来处理的。而 history 模式是基于 html5 中 history 新增的一些api. hisotry.pushState() history.replaceState() window.onpopstate 来实现的,window.popstate点击浏览器的前进和后退按钮可以触发。
- hisotry模式还需要后台配置去处理上线的404的问题,上线如果不处理,默认是访问dist里面的地址,会自动跳转到首页,但是如果一刷新,就是访问http://localhost:8080/home/page1,而dist中没有哦home文件夹,就会报404,找不到文件。
vue 导航守卫
主要分为三个大块
- 全局
- 全局前置 beforeEach
- 全局解析守卫 beforeResolve ,一般很少用到
- 全局后置 afterEach
- 路由独享的
- beforeEnter 进入当前路由时
- 组件级别的
- beforeRouteEnter 进入当前组件时
- beforeRouteUpdate 当前组件更新时
- beforeRouteLeave 退出当前组件时
全局前置守卫(beforeEach)
接收一个函数,函数中有三个参数:to,form,next,分别代表要去的路由,来自哪个路由,是否让它去。
- next:
- 1、如果直接调用,那么就相当于放行。
- 2、如果调用,但是传递了一个false,就是不放行。
- 3、如果不调用,也是不放行。
- 4、调用并且里面可以传递路由的path路径或者是路由的对象信息。那么就重定向到我们的参数所指定的url地址。一般不会直接传递url地址,传地址会造成死循环,从index去detail,去detail又会触发beforeEach,又去到detail。
nprogress进度条插件可以配合全局前置守卫和全局后置守卫实现进度条的效果。
导航守卫的钩子函数
在路由发生变化的时候会主动触发的一些函数
作用场景
- beforeEach 与 afterEach 能实现页面进度条的效果
- 登录拦截
1、 先排除 组件级别
2、 afterEach 排除
3、正常情况下,如果是后台管理系统的话,因为处理登录与注册页面之外其他的都需要做登录的拦截,那么就可以再 全局前置 里面去做。如果项目中只有那么一个到两个需要做拦截的页面,那么就可以再他们自己的路由独享里面去做。
使用beforeEach做路由拦截
router.beforeEach((to,from,next) =>{
NProgress.start()
// 路由拦截
// 判断是否去卖座卡页面或者余额页面
if ( to.path === '/card' || to.path === '/money' ){
// 判断是否有登陆
if ( window.localStorage.getItem('userInfo')) {
// 登陆了,让它去
next()
}else{
// 没登陆,跳去登陆页面
// next('/login')
// 传参数过去,知道是想去哪里点击的登陆
next({
path: '/login',
query: {
// redirect: to.path // 想去哪个页面,通过query传递过去,或者name和params传递
// 通过to.path获取到想去的页面,如果带有参数,to.path是不能传递参数过去的。
redirect: to.fullPath // to.fullPath 能拿到传递的参数(url?后面的参数)
}
})
}
}else{
next();
}
})
login页面可以接受并作出相应的跳转
// 接收传递过来想去的页面地址
// let toPage = this.$route.query.redirect;
//如果用户直接通过login页面登陆,没传递参数,就让他跳转到个人中心页面
let toPage = this.$route.query.redirect || '/center';
this.$router.replace(toPage)
一般使用多个页面需要拦截使用beforeEach来做路由拦截,一两个用brforeEnter路由独享做拦截,路由独享做拦截会使代码比较臃肿,因为拦截的代码大致一样。
路由元信息
定义路由的时候可以配置 meta 字段,就可以知道这个路由需要拦截。
{
path: '/money',
component: Money,
name: 'money',
meta: {
requireLogin: true
}
}
下面判断只需要判断meta就可以了
router.beforeEach((to,from,next) =>{
if(to.meta.requireLogin){
}else{
next();
}
}
动态路由匹配
当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象:
watch: {
$route (newVal,oldVal) {
this.getGoods()
}
}
或者使用 beforeRouteUpdate(当前路由更新是)的导航守卫:
beforeRouteUpdate (to,from,next) {
console.log('当前组件更新')
let newId = to.params.id;
// 更新进入之后,还没next,url地址还没变,所以要从to里面拿到去哪个地址新的id
this.getGoods(newId);
next()
}
路由的懒加载
需要哪个组件就加载哪个组件。
routes: [
{
path: '/',
// 可以在文件路径前加上/* webpackChunkName: "group-foo" */设置network请求的js名字
component: ()=> import(/* webpackChunkName: "index" */'../views/index/index.vue'),
children: [
{
path: 'home',
component: ()=> import('../views/index/home.vue'),
}
}
]