Vue router

92 阅读3分钟

基础

1 起步

命名路由:通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。

你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。

配置路由 注意name,添加name属性则为命名路由。

// router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
const routes = [
  {
    path: "/",
    name: "Home",
    component: Home
  },
  {
    path: "/about",
    name: "About",
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    //懒加载,可以优化路由性能
    component: () =>
      import(/* webpackChunkName: "about" */ "../views/About.vue")
  },
  {
    path: '*', 
    redirect: '/'   // 默认加载路由, 输入地址没有匹配上,则会匹配地址为 /  的路由
  },
 // { // 会匹配所有路径 
 // path: '*',
 //  component: () => import('../views/404.vue')  // 通配符 适合做404页面路由
 // }
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes
});

export default router;


// main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
Vue.config.productionTip = false;

//挂载路由
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app");



// app.vue
<router-link to="/">go to home</router-lnk>
<router-link to="/about">go to about</router-link>动态


<router-view></router-view>  

2 动态路由配置

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对 于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中 使用“动态路径参数”(dynamic segment) 来达到这个效果:

//1  配置动态路由
{
    path: '/test/:name',   // 动态路径参数 以冒号开头
    component: () =>import( "../views/test.vue")
}

//2  页面   两种方式 动态绑定   router-link 将当前的dom元素变成超链接
<router-link :to="`/test/${name}`">
	{{name}}go to test.vue
</router-link>
<router-link :to="'/test/'+name">
	{{name}}go to test.vue
</router-link>

//3  获取路由的值
 this.$route.params获取动态路由的值

3 嵌套路由

实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构 对应嵌套的各层组件

//路由配置
{
    path: "/about",
    name: "About",
    component: () => import("../views/About.vue"),
    children:[
      {
        path:':name',
        name:'detail',
        component:() => import("../views/Detail.vue"),
      }
    ]
  },

//父路由配置
<router-link :to="`/about/${name}`">
      {{name}} go to detail.vue
</router-link>

<router-view></router-view> // 嵌套内容出口

//3  获取路由的值
 this.$route.params获取动态路由的值

4 命名路由

通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。 你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。

  {
    path: '/mobile/:name', 
    name:"mobile",
    component: () =>
       import("../views/contact/mobile.vue")
  },
  
// 要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象:
<router-link :to="{name:'mobile',params:{name:'张三',mobile:'139'}}"></router-link>

//调用router.push()

router.push({ name: 'mobile',params:{name:'张三',mobile:'139'}})

5 编程导航

//路由跳转  跳转location地址  onComplete 路由跳转完成后调用, onAbort取消跳转后调用
this.$router.push(location,onComplete?,onAbort?);

// 字符串 
this.$router.push('home') 

// 对象  path:地址
this.$router.push({ path: 'home' }) 

// 命名的路由 name  router名称=>path的值
this.$router.push({ name: 'user', params: { userId: '123' }}) 

// 带查询参数,变成 /register?plan=private 
this.$router.push({ path: 'register', query: { plan: 'private' }})

//示例
methods: {
    onClick() {
    	this.$router.push({ path: 'register', query: { plan: 'private' }})
    }
},


//组件复用时注意事项:
//响应路由参数变化
watch: {
    $route: { // 用户自定义watcher
        immediate: true,
        deep: true,
        handler() {
      	  console.log("路由变化之后 执行动作");
        }
    }
},

进阶

路由守卫

1 全局守卫

//全局路由守卫
router.beforeEach((to,from,next)=>{
 //to: Route即将要进入的目标 路由对象
 // from: Route当前导航正要离开的路由
 // next:Function 一定要调用该方法来resolve这个钩子
});

// 范例: 守卫 About.vue
1、配置路由
  {
    path: "/about",
    name: "About",
    component: () => import("../views/About.vue"),
    children:[
      {
        path:':name',
        name:'detail',
        component:() => import("../views/Detail.vue"),
      }
    ],
    meta:{
      auth:true
    }
  },
  {
    path:'/login',
    component:()=>import('../views/Login.vue'),
  },
  
2 配置全局守卫
router.beforeEach((to,from,next)=>{
  if(to.meta.auth){
    if(window.isLogin){
       next();
     }else{
       next('/login?redirect='+to.fullPath); // redirect查询参, 回到跳转时的路由
     }
  }else{
    next();
  }
});

3 访问
this.$router.push(this.$route.query.redirect);

2 独享守卫

{
    path: "/about",
    name: "About",
    component: () => import("../views/About.vue"),
    children:[
      {
        path:':name',
        name:'detail',
        component:() => import("../views/Detail.vue"),
      }
    ],
    meta:{
      auth:true
    },
    beforeEnter(to,from,next){
        if(window.isLogin){
          next();
        }else{
          next('/login?redirect='+to.fullPath);
        }
    },
  },

3 组件内守卫

可以在组件内直接定义以下路由导航守卫

beforeRouteEnter // 进入目标路由之前触发
beforeRouteUpdate // 当前路由参数发生变化  比如动态路由
beforeRouteLeave  //离开当前路由触发

// About.vue
<script>
export default {
  data() {
    return {
      name: "李四",
    }
  },
   beforeRouteEnter(to,from,next){
   if(window.isLogin){
     next();
   }else{
     next('/login?redirect='+to.fullPath);
   }
 },
}
</script>

4 数据获取

1 路由导航前

// 组件未渲染,通过给next传递回调访问组件实例 
beforeRouteEnter (to, from, next) { 
  getPost(to.params.id, post => {
     next(vm => vm.setData(post)) 
  }) }, 
// 组件已渲染,可以访问this直接赋值 
beforeRouteUpdate (to, from, next) { 
  this.post = null 
  getPost(to.params.id, post => { 
     this.setData(post) next() 
  }) 
},

2 路由导航后

created () { 
    this.fetchData() 
}, 
watch: { 
  '$route': 'fetchData' 
}

动态路由

根据用户角色通过router.addRoutes(routes)方式动态添加路由

// 全局守卫修改为 : 要求用户必须登录,否则只能去登录页面

router.beforeEach((to,from,next)=>{ // 全局守卫
    if(window.isLogin){//已经登录
       if(to.path === '/login'){
          next('/');
       }else{
         next();
       }
     }else{// 没有登录
       if(to.path === '/login'){
         next();
       }else{
        next('/login?redirect=' + to.fullPath);
       }
      next();
    }
});


// login.vue 用户登录成功后动态添加路由   /about

login(){
    window.isLogin=true;
    this.$router.addRoutes([
       {
         path:'/about', 
         // ......
       }
    ]);
    this.$router.push(this.$route.query.redirect || '/'); // 跳转路由
}

路由缓存

注意: 使用include 或exclude时 要给组件设置name

//利用keepalive做组件缓存,保留组件状态,提高执行效率

// 范例 缓存 about组件
// about 的值为  组件的名称  , 多个名称用 ',' 隔开
// 仅缓存about组件  max表示最多缓存的组件数量,超过后先进先出
<keep-alive include='about' max='10'>   
	<router-view />
</keep-alive>

// 除了about组件外,其他组件都缓存
<keep-alive exclude='about'>   
	<router-view />
</keep-alive>

// aboute组件
export default {
  name:'about',
  data() {
    return {
      name: "李四",
      school:[],
    }
  },
 }
 
 
 
// 两个特别的生命周期钩子 
// 当设置 缓存about时, 进入about时会触发activated钩子,离开aboute会触发deactivated
export default {
  name:'about',
  data() {
    return {
      name: "李四",
      school:[],
      
    }
  },
  activated(){
    console.log('activated');

  },
  deactivated(){
    console.log('deactivated');

  },
 }

路由懒加载

路由组件的懒加载能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

() => import("../views/About.vue")
//把组件按组分块
() => import(/* webpackChunkName: "group-about" */ "../views/About.vue")