vue-router 学习整理

概述

vue-router是vue-cli中管理路由的模块
通过URL,实现URL和组件之间的一一对应,通过URL进行组件 切换

应用场景:
单页面应用 single page application(SPA) 移动端应用很广泛, 没有真实的页面跳转,只是针对不用URL在页面内容区域做了不同的渲染
只是加载一次JS、CSS文件,降低了页面切换时候的 HTTP请求

安装方式

1.一般在vue-cli初始化(vue init webpack 项目名称)时候,会有提示 是否安装vue-router,选择y回车,即可安装
2.后续手动安装,命令行到指定目录
输入:

npm install vue-router --save   //安装vue-router并添加到依赖
使用

以将代码放置在入口文件main.js为例

import Vue from 'vue'
import App from './app'
//1.引入模块
import VueRouter from 'vue-router' 

//2.将vue-router作为Vue的插件
Vue.use(VueRouter)

//3.创建vue-router实例
let router = new VueRouter({
  ...
})

//4.将路由配置信息router挂载到Vue实例
new Vue({
  el: '#app',
  router,  
  template: '<app />'
  components:{
    App    //App为跟组件 App.vue 
  }
})
配置路由

let router = new VueRouter({ ... })
说明:为什么命名router
router是我们的路由实例,命名为变量router是为了方便简写,在Vue实例上有个键名叫router,两者相同则可以写一个键名即可

1.简单配置路由

new VueRouter({
  mode:'history',  //模式分为 hash,history两种,默认为hash
  linkActiveClass:'xxx', //当前处在激活状态下的router-link标签上的状态class名
  scrollBehavior(to,from,saveposition){   //滑动信息 
    ...
  },
  routes:[  //路由调整信息
    {
      path:'/',  //这个是路径
      component:xxx,  //这个是对应import过来的单文件组件,作为模板
      alias:'/index',  //访问另一个路径,扔可以访问,但是不会触发按钮的激活类名
      name:'indexpage' ,
      meta:{      //定义针对当前路由的自定义数据
        needlogin:true
      }
   },{
      path:'/about',
      component:xxx
    },{
      path:'*',    //通配符,标识没有配置路由的路径情况,一般作为404
      redirect:{    //重新定向到一个已经存在的路由路径
        path:'xxxx'  
      }
    }
  ]
})

另外,配置路由,引入模板时候,在vue-cli中 @标识src文件夹,可以在webpack.base.conf.js 查看其声明

2.关于配置路由中的mode选择

new VueRouter({
  mode:'hash',    //如果选择hash模式,链接中需要带#
  routes:[
    ...
  ]
})

建议:
一般低版本浏览器使用hash模式
高版本浏览器使用history模式

3.关于配置路由中的重定向redirect

  redirect((to)=>{      //通过箭头函数,参数to,可以获取path路径,可以更加丰富我们重定向的逻辑
    if(to.path=='xxx'){
      return '/my';  //跳转到我的
    }else{
      return '/';  //跳转到首页
    }
  })

  //redirect书写的方式
  redirect:'/about'
  redirect:{path:'/about'}
  redirect:{name:'xxx'} //通过routes中的name,也可以定位 

4.存在二级路径嵌套时候
默认显示第一项的需求
在二级嵌套中,如果希望父路由默认显示第一个子路由信息,且子路由为激活状态
则可以将父路由path:'',将子路由的第一项path设置为父路由原有path

  ...
  {
    path: '/about',
    component: 'xxx',
    children:[
      {
        path:'/about/xxx',    //二级子菜单
        component:'xxxx'
      }
    ]
  }
  ...

使用children嵌套数据,将子路由对象放进去

5.路由是我们配置浏览器跳转的基本配置,在模板页面中我们需要使用连接来触发

<router-link>我是个按钮</router-link>

router-link属性:
to="xxx" //相当于a标签的href,填写跳转链接
tag="li"  //将<router-link>渲染为什么标签,以便浏览器去渲染
event="hover" //如果要添加一个触发事件,则用event来声明,默认click
active-class="xxx"  
//如果标签对应的,路由路径为当前状态,则vue-router会默认为其添加激活的状态类名
//如果你想自定义自己的激活状态class名,则用这个
//另外,自定义状态类名有2个位置,一个在路由配置中,一个在这个触发按钮上,
//同时配置,按钮的优先级高,会剔除掉路由上的激活状态配置类名

exact 
//如果不采用相对于根路径 /xxx  那么有可能存在,父路由,子路由同时处于激活class名状态下
//此时,添加exact 严格模式,以便只有一个路由显示激活class名      

6.对应path有router-link,对应的component,应该渲染到这里<router-view>

<router-link to="xxxx" tag="li">
  <a>按钮1</a>    //如果router-link要嵌套a标签,则a标签不用再写href了
</router-link>
<router-link to="xxxx" tag="li">
  <a>按钮2</a>
</router-link>
//多个按钮对应一个router-view
<router-view></router-view>

7.命名视图
在路由配置的routes中 path和component是一一对应的,
如果我们希望某一个path对应多个component时候
如:

//在路由配置文件中
  path:"/about",
  components:{    //注意 components 是复数形式
    default: "模板1",  //不写name的view-router为default
    slider: "模板2"  
  }

//在单文件组件中
//当我们访问 /about 时候,下面2个router-view会同时显示
<router-view></router-view>
<router-view name="slider"></router-view>

//在router-view中可以添加class名,
<router-view class="father-box"></router-view>  //router-view中的所有结构都有一个父级class名为father-box

//在单文件组件中
<template>
  <div class="son-box">
      <p>hello</p>
  </div>
</template>

//渲染后
<div class="father-box son-box">  //类名会进行合并
    <p>hello</p>
</div>

8.路由配置中的scrollBehavior
在页面onload或者浏览器前进,后退时候触发

scrollBehavior(to,from,saveposition ){
   //to 目标路由
   //from 当前路由
   //saveposition 当前位置
   //可以将当前  saveposition 作为返回值,达到页面跳转,返回后恢复滚动条位置的效果

   //滚动条滑动顶部位置
   return { x: 0, y: 0 };
}

8.动态路由
在路由配置中,所有的path都是以一个可预测的状态存在
如果我们希望添加一个格式,不清楚具体数据,需要使用动态路由

  //在路由配置中  
  ...
  {
    path:'/students/:userId?',  //其可以匹配 /students,/students/1,/students/2
    component:'xxx'
  }  
  ...
  
  //在单文件组件页面
  通过 this.$route.params.userId 可以获取其信息,使得后续逻辑上更加丰富

9.路由的自定义属性

  ...
  {
    path:'xxxx',
    component:'xxxx',
    meta:{
      needlogin:true
    }
  }
  ...

  //在单文件组件中,我们可以通过$route中获取
  this.$route.meta.needlogin
  1. 动态路由的传参的新方式,配置props: true
  • 通常方式
//---路由部分
routes:[
  {
    path:'/categories/edit/:id?' 
    component:'xxx'
  }
]
//---单文件组件中
created(){
   console.log(this.$route.params.id);
}
  • 新的传递params方式:
    路由中props为true,代表将连接中任何参数,以props方式注入到新组件中去
//---路由部分
routes:[
  {
    path:'/categories/edit/:id?' 
    component:'xxx',
    props: true
  }
]
//---单文件组件中
props:[
  'id'
]
router 与 $route

router是我们创建的VueRouter实例
$route是当前单文件组件的路由实例

router实例方法 实现 【编程式导航】

//直接跳转
router.push('/about')
router.push({ path: '/about' })

//动态路由,单文件页面通过 this.$route.params.userId 获取传递信息
router.push({ name: 'about', params: { userId: '123' }})

//查询字符串方式,用户访问有权限的页面,直接跳转到登录页,
//登录完成后,通过this.$route.query.redirect 获取用户之前想去的页面,然后通过push,再次跳转
//实现 未登录状态->登录->登录后自动跳转用户之前想去的 权限限制页面
router.push({ path: '/login', query: { redirect: '/user' }})

其他方法:

  router.repalce( '/xxx' ) 
//将历史记录中的当前步骤替换掉,并且完成跳转

  router.go(number)  
  // 填写具体数字,针对history的当前步数,向前是负值,向后是正值,但是只能在历史步数内,超过则不作操作

vue-router生命周期 钩子

全局钩子函数

所有路由进入,出去都会触发此钩子函数

  1. beforeEach
    还没有进入路由内,所有不能获取vue实例
    如果此时此刻想获取,可以通过router.app方式,得到vue实例
let router = new VueRouter({...})

router.beforeEach(function(to,from,next){
    console.log(to); //目标导航
    console.log(from);  //离开导航
    next(); //执行则路由跳转

    //实际例子,根据路由情况,判断是否需要登录
    //根据目标路径下的 自定义属性meta(如果你设置了),如 
    ...
    {
        path:'/xxx'
        component:'xxx',
        meta:{              //meta提供开发者挂载自定义数据
            needLogin:true      //xxx页面需要登录
        }
    }
    ...

    //如果跳转到xxx页面,则跳转到登录/login,否则路由正常跳转
    if(to.meta.needLogin){
        next('/login');
    }else{
        next();
    }

})
  1. afterEach
rourer.afterEach(function(to,from){
    //路由跳转后,我们可以做一些操作
    //例如: 根据path或者meta添加新属性,去判断,改变文档标题

    if(to.path=='/'){
        window.document.title = 'xxx'
    }else if{
        ...
    }else{
        ...
    }
});

局部钩子函数

beforeEnter 针对某一个路由,进行处理

  ...,
  {
    path:'xxx'
    component:'xxx',
    beforeEnter(to,from,next){
        //只是针对xxx这个path,做操作
        next();  //next必须执行,否则会卡住
    }   
  },
  ...
单文件组件中的钩子函数
优先顺序从【0】开始

<script>
data(){
    return{
        msg:'hello'
    }
},
created(){
     console.log("创建完成:");
     console.log(this.$el);
},
beforeCreate(){  【2】
    //组件执行的第一个钩子函数   
},
beforeRouteEnter(to,from,next){【1】
    //访问导航时候,执行这个路由执行的第一的函数   
    //这个时候组件还没有初始化,无法访问this

    console.log(this) //undefined

    next(function(vm){  //next中函数的参数,参数vm就是vue实例
        //vm就是当前组件实例
        console.log(vm.msg);  //'hello'
    })
},
beforeRouteUpdata(to,from,next){
    //这个是路由嵌套情况下,点击子导航触发
    console.log('beforeRouteUpdata');
      
    next(); //不写这个钩子函数不会继续执行

        console.log(this) //可以访问组件实例
},
beforeRouteLeave(to,from,next){
    //离开主导航(主组件)时候触发
}

</script>

路由的细节问题

  1. 同一个路由地址,query参数不同,点击通过$router.push从当前路由地址,跳转到当前路由地址,参数变化
//传值
this.$router.push({path:"/menLink",query:{alert:"页面跳转成功"}})
//用query获取值
<p>提示:{{this.$route.query.alert}}</p>

页面不重新渲染的情况,只需要对 <router-view></router-view> 增加属性key

 <router-view :key="$route.fullPath" ></router-view>

1-2. 当两个不同的path,对应相同的component的时候;
在两个路由之间切换,不会改变router-view视图更新
如:

{
  path: '/create',
  component:Categories
},{
  path: '/edit/:id',
  component:Categories
}

解决方法:
绑定key属性

<router-view :key="$route.path"></router-view>

1-3.当两个相同的path,对应相同的component的时候;
在两个路由之间切换,不会触发created的生命周期函数,不会对router-view进行视图更新
如:

{
  path: '/article/:id',
  component:Article
}

id=1 与 id=2 两个情况,切换时候碰到
解决方法:
需要针对id进行watch,之后强制触发created中的数据获取函数
如:

watch:{
  id : function(){
    //请求对应ID下的数据,进行视图渲染
    this.getDataByIdFn();
  }
},
created(){
  //默认进入获取
  this.getDataByIdFn();
}
  1. ios 和 safari下,相同path但query修改,跳转后,会出现页面不渲染的情况,因此使用window.location.reload刷新页面
this.$router
.push({ path: "/college", query: { DeptInfo: id } })
.then(() => {
    window.location.reload();
});

生命周期相关

组件内路由

  • beforeRouteEnter
beforeRouteEnter(to, from, next){
    // 无法获取this,只能通过vm获取
    next(vm => {
      vm.routeFrom = from.name
      vm.routeTo = to.name
    })
}
  • beforeRouteLeave
beforeRouteLeave(to, from, next){
    this.routeFrom = from.name
    this.routeTo = to.name
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容