Vue.js vue-router 路由

2021/4/29 Vue Routerkeep-aliveVue

# vue-router

# 起步

Home.vue

<template>
  <div>
    <h1>Home</h1>
  </div>
</template>
1
2
3
4
5

App.vue

<template>
  <div id="app">
    <router-link to = "/home"  replace>首页</router-link>
    <router-view></router-view>
  </div>
</template>
1
2
3
4
5
6

index.js

import Home  from "../components/User";
Vue.use(Router)
export default new Router({
  routes: [
    {
      path: '/home',
      name: 'home',
      component: Home,
    }
  ]
})
1
2
3
4
5
6
7
8
9
10
11

# 路由重定向

使用redirect默认将Home设为首页

index.js

routes: [
    {
      path: '/',
      redirect:'/home'
    },
    {
      path: '/home',
      name: 'home',
      component: Home,
    }
  ]
1
2
3
4
5
6
7
8
9
10
11

# Hash与History模式

  • vue-router默认hash模式, ur使用 # 后面定位路由,对seo不利,设置history,就可以使用普通的url模式

  • history模式即普通url模式,这种模式充分利用history.pushState API来完成URL跳转而无须重新加载页面

# 修改为history模式

export default new Router({
  routes: [
    {
      path: '/home',
      name: 'home',
      component: Home,
    }
  ],
  mode:'history' //加入属性history
})
1
2
3
4
5
6
7
8
9
10
 <router-link to = "/home"  replace>首页</router-link>
1
  • tag

tag属性可以更改router-link的渲染的组件

 <router-link to = "/home" tag="button">首页</router-link>
1
  • replace

设置不能返回

 <router-link to = "/home" tag="button" replace>首页</router-link>
1
  • router-link-active

路由匹配成功时,会自动给当前元素设置一个router-link-active的class

例如设置点击变色

.router-link-active{
  color: cornflowerblue;
}
1
2
3

# 通过代码跳转路由

通过$router.push跳转

HTML

 <button @click = "homeClick">首页</button>
1

JS

methods:{
    homeClick(){
      this.$router.push('/home').catch(err=>{err})
    }
}
1
2
3
4
5

# 动态路由

可以接收参数数据的路由形式,路由地址的一部分是会发生变化的

# 1. 通过$route.params传递参数

App.vue

HTML

<router-link :to = "'/user/'+userId"  replace></router-link>
<router-view :my-name="userId"></router-view>
1
2

JS

data(){
    return{
      userId:'Okarin'
    }
  }
1
2
3
4
5

User.vue

HTML

<template>
  <div>
    <h3>{{userId}} is my name</h3>
  </div>
</template>
1
2
3
4
5

JS

  computed:{
    userId(){
      return this.$route.params.userId
    }
  }
1
2
3
4
5

index.js

{
      path:'/user/:userId', //:后面接参数名字
      name:'user',
      component:User
    }
1
2
3
4
5

# 2. 通过props属性传递

App.vue

HTML

<router-view :my-name="userId"></router-view> 
1

JS

data(){
    return{
      userId:'Okarin'
    }
  }
1
2
3
4
5

User.vue

HTML

<template>
  <div>
    <h1> Hello {{myName}}! </h1>
  </div>
</template>
1
2
3
4
5

JS

  props:{
    myName:{
      type:String,
      dafult:'Retr0',
      required:true
    }
1
2
3
4
5
6

index.js

{
      path:'/user/:userId', //:后面接参数名字
      name:'user',
      component:User
    }
1
2
3
4
5

# 3. 通过query属性传递

App.vue

HTML

 <router-link :to ="{path:'/profile',query:{name:'Okarin',age:'18',words:'EL PSY CONGROO!' } }" replace>个人</router-link>
1

Profile.vue

HTML

<template>
  <div>
    <h1>{{profileInfo.name}}</h1>
    <h2>Age: {{profileInfo.age}}</h2>
    <h3>{{profileInfo.words}}</h3>
  </div>
</template>

1
2
3
4
5
6
7
8

JS

  computed:{
    profileInfo(){
      return this.$route.query
    }
  }
1
2
3
4
5

# 通过代码跳转传递参数

App.vue

HTML

<button @click = "profileClick">我的</button>
1

JS

    profileClick() {
      this.$router.push({
        path:'/profile',
        query:{
          name:'retr0',
          age:'19',
          words:'let us coding!' }
      })
    }
1
2
3
4
5
6
7
8
9

# 路由懒加载

分组件打包js

index.js

const Home = () => import( "../components/Home");
// import Home  from "../components/User"; 对比
1
2

# 嵌套路由

index.js

{
      path: '/home',
      name: 'home',
      component: Home,
      children:[
        {
          path: '/',
          redirect:'news'
        },
        {
          path:'news',
          component:HomeNews
        },
        {
          path:'message',
          component:HomeMessage
        }
      ]
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Home.vue

HTML

<template>
  <div>
    <h1>Home</h1>
    <router-link to = "/home/news">新闻</router-link>
    <router-link to = "/home/message">消息</router-link>
    <router-view/>
  </div>
</template>
1
2
3
4
5
6
7
8

# 全局导航守卫

可以用来做用户在没有登录注册时的拦截 使用 router.beforeEach(前置钩子函数) 注册一个全局前置守卫:

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
})
1
2
3
4
5

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象
  • from: Route: 当前导航正要离开的路由
  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

# 设置网页标题

index.js

{
      path:'/about',
      meta:{
        title:'关于'
      },             //使用meta元数据
      name:'about',
      component:About
    }


router.beforeEach((to, from, next) => {
  document.title = to.matched[0].meta.title
  next()
})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 全局守卫补充

  • afterEach(后置钩子)

# 组件中的守卫

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# vue router 与 keep-alive

使用$route.meta的keepAlive属性:

<keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
1
2
3
4

需要在router中设置router的元信息meta:

//...router.js
export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: Hello,
      meta: {
        keepAlive: false // 不需要缓存
      }
    },
    {
      path: '/page1',
      name: 'Page1',
      component: Page1,
      meta: {
        keepAlive: true // 需要被缓存
      }
    }
  ]
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

使用效果

以上面router的代码为例:

<!-- Page1页面 -->
<template>
  <div class="hello">
    <h1>Vue</h1>
    <h2>{{msg}}</h2>
    <input placeholder="输入框"></input>
  </div>
</template>
1
2
3
4
5
6
7
8
<!-- Hello页面 -->
<template>
  <div class="hello">
    <h1>{{msg}}</h1>
  </div>
</template>
1
2
3
4
5
6

(1) 在Page1页面输入框输入“asd”,然后手动跳转到Hello页面;

(2) 回到Page1页面发现之前输入的"asd"依然保留,说明页面信息成功保存在内存中;

进入Page1页面,并输入"asd"

跳转到Hello

返回Page1页面,输入框数据会被保留

当然,也可以通过动态设置route.meta的keepAlive属性来实现其他需求

首页是A页面 B页面跳转到A,A页面需要缓存 C页面跳转到A,A页面不需要被缓存 思路是在每个路由的beforeRouteLeave(to, from, next)钩子中设置to.meta.keepAlive

A的路由:

{
    path: '/',
    name: 'A',
    component: A,
    meta: {
        keepAlive: true // 需要被缓存
    }
}
export default {
    data() {
        return {};
    },
    methods: {},
    beforeRouteLeave(to, from, next) {
         // 设置下一个路由的 meta
        to.meta.keepAlive = true;  // B 跳转到 A 时,让 A 缓存,即不刷新
        next();
    }
};
export default {
    data() {
        return {};
    },
    methods: {},
    beforeRouteLeave(to, from, next) {
        // 设置下一个路由的 meta
        to.meta.keepAlive = false; // C 跳转到 A 时让 A 不缓存,即刷新
        next();
    }
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Last Updated: 2021/12/19上午12:27:30