Vue路由(vue-router)详细讲解指南

中文文档:https://router.vuejs.org/zh/

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。路由实际上就是可以理解为指向,就是我在页面上点击一个按钮需要跳转到对应的页面,这就是路由跳转;

首先我们来学习三个单词(route,routes,router):

  route:首先它是个单数,译为路由,即我们可以理解为单个路由或者某一个路由;

  routes:它是个复数,表示多个的集合才能为复数;即我们可以理解为多个路由的集合,JS 中表示多种不同状态的集合的形式只有数组和对象两种,事实上官方定义 routes 是一个数组;所以我们记住了,routes 表示多个数组的集合;

  router:译为路由器,上面都是路由,这个是路由器,我们可以理解为一个容器包含上述两个或者说它是一个管理者,负责管理上述两个;举个常见的场景的例子:当用户在页面上点击按钮的时候,这个时候 router 就会去 routes 中去查找 route,就是说路由器会去路由集合中找对应的路由;

 

我们结合一个小 demo 来看(文章有点长,耐心慢慢看,学得慢才能进步的快,当然可以跟着一起敲):

  首先需要安装 vue-cli 来构建一个 vue 的开发环境(怎么安装这里不讲,自己百度去,如果这种问题自己都解决不了的话,后面的知识可能对你来说收益不大)

  安装完 vue-cli 之后,我们的项目目录结构如下:

   

 

 

   然后我们在命令行中输入 npm install vue-router -g 来安装 vue-router,安装完之后我们可以打开 package.json 文件,在 package.json 文件中可以看到 vue-router 的版本号;

 

 

 到这一步我们的准备工作就完成了,要进行写 demo 了;

 

我们在 src 目录下新建三个文件,分别为 page1.vue 和 page2.vue 以及 router.js:

page1.vue:

 

<template>
    <div>
        <h1>page1</h1>
        <p>{{msg}}</p>
    </div>
</template>
<script>
    export default {data () {
            return {
                msg: "我是 page1 组件"
            }
        }
    }
</script>

 

 page2.vue:

 

<template>
    <div>
        <h1>page2</h1>
        <p>{{msg}}</p>
    </div>
</template>
<script>
    export default {data () {
            return {
                msg: "我是 page2 组件"
            }
        }
    }
</script>

 

router.js

//引入 vue
import Vue from 'vue';
//引入 vue-router
import VueRouter from 'vue-router';
//第三方库需要 use 一下才能用
Vue.use(VueRouter)
//引用 page1 页面
import page1  from './page1.vue';
//引用 page2 页面
import page2  from './page2.vue';

//定义 routes 路由的集合,数组类型
const routes=[
//单个路由均为对象类型,path 代表的是路径,component 代表组件
{path:'/page1',component:page1},
{path:
"/page2",component:page2}
]

//实例化 VueRouter 并将 routes 添加进去
const router=new VueRouter({
//ES6 简写,等于 routes:routes
routes
});

//抛出这个这个实例对象方便外部读取以及访问
export default router

这里我们再修改一下 main.js

import Vue from 'vue'
import App from './App'
//引用 router.js
import router from './router.js'
Vue.config.productionTip = false

/ eslint-disable no-new /
new Vue({
el:
'#app',
//一定要注入到 vue 的实例对象上
router,
components: {App},
template:
'<App/>'
})

修改 App.vue

  

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <div>
//router-link 定义页面中点击触发部分  
      <router-link to="/page1">Page1</router-link>
      <router-link to="/page2">Page2</router-link>
    </div>
//router-view 定义页面中显示部分
    <router-view></router-view>
  </div>
</template>

<script>
export
default {
name:
'App'
}
</script>

<style>
#app {
font
-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text
-align: center;
color: #2c3e50;
margin
-top: 60px;
}
</style>

 

就这样,我们的页面就可以进行路由跳转和切换了,路由的基本使用就完成了;但是有个问题就是我们第一次进去是看不到路由页面的,这是因为我们没有设置默认值,我们首次进入的时候路径是为空的,那么我们可以这么解决:

router.js

 

import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter)
import page1  from './page1.vue';
import page2  from './page2.vue';
import user   from './user.vue'

const routes=[
{path:
'/page1',component:page1},
{path:
"/page2",component:page2},
//可以配置重定向
{path:'',redirect:"page1"}
//或者重新写个路径为空的路由
{path:"",component:page1}
]

const router=new VueRouter({
routes
});

export default router

 

上面的两种解决方案都是可以解决的,配置重定向的意思就是当匹配到路径为空的时候,就会重定向到 page1,执行 page1 的路由;或者我们也可以重新配置个路由,路径为空的时候 router-view 展示 page1 的页面;

用重定向和单独配置路由的区别:

  重定向实际上是当匹配到路径符合条件的时候去执行对应的路由,当然这个时候的 url 上面的地址显示的是对应的路由,页面也是对应的路由页面;

  重新配置路由是当匹配到路径符合条件的时候,router-view 页面展示部分负责拿符合条件路由的页面来展示,实际上 url 是没有发生变化的;

 

那么还有些复杂情况,是基本路由实现不了的;我们来接着往下看

 

动态路由匹配:

  其实我们的生活中有很多这样的例子,不知道大家留意没有?比如一个网站或者后台管理系统中,在我们登录之后,是不是通常会有一个欢迎回来,XXX 之类的提示语,这个我们就可以通过动态路由来实现这个效果;

 

首先在 src 目录下新建一个 user.vue 文件:

<template>
    <div>
        <h1>user</h1>
       //这里可以通过 $route.params.name 来获取路由的参数
        <p> 欢迎回来,{{$route.params.name}}</p>
    </div>
</template>
<script>
    export default {data () {
            return {
                msg: "我是 page1 组件"
            }
        }
    }
</script>

 

然后我们修改 App.vue 文件的代码:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <div>
      <router-link to="/page1">Page1</router-link>
      <router-link to="/page2">Page2</router-link>
    </div>

//添加两个 router-link 标签
<div>
<router-link to="/user/xianyu"> 动态路由咸鱼 </router-link>
<router-link to="/user/mengxiang"> 动态路由梦想 </router-link>
</div>
<router-view></router-view>
</div>
</template>

<script>
export
default {
name:
'App'
}
</script>

<style>
#app {
font
-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text
-align: center;
color: #2c3e50;
margin
-top: 60px;
}
</style>

修改我们的 router.js

import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter)
import page1  from './page1.vue';
import page2  from './page2.vue';
import user   from './user.vue'

const routes=[
{path:
'/page1',component:page1},
{path:
"/page2",component:page2},
// {path:'',redirect:"page1"}
{path:"",component:page1},
//使用冒号标记,当匹配到的时候,参数值会被设置到 this.$route.params 中
{path:"/user/:name",component:user}

]

const router=new VueRouter({
routes
});

export default router

配置好了,不出意外是能正常运行的,我们来看一下效果:

 

 

 动态路由匹配给我们提供了方便,使得我们通过配置一个路由来实现页面局部修改的效果,给用户造成一种多个页面的感觉,是不是很酷!!!

酷的同时也会给我们带来一些问题,因为使用路由参数时,从 /user/xianyu 导航到 /user/mengxiang,原来的组件实例会被复用,两个路由都渲染同个组件,比起销毁再创建,显示复用显得效率更高,带来的的只管问题就是生命周期钩子函数不会再被调用,也就是不会再被触发;但是办法总比问题多,我们可以通过监听 $route 对象来实现;

修改 user.vue 的代码

<template>
    <div>
        <h1>user</h1>
        <p> 欢迎回来,{{msg}}</p>
    </div>
</template>
<script>
    export default {data () {
            return {
                // msg: "我是 page1 组件"
                msg:""
            }
        },
        watch:{
//to 表示即将要进入的那个组件,from 表示从哪个组件过来的
            $route(to,from){
                this.msg=to.params.name; 
                console.log(111);}
        }
    }
</script>

效果图如下:

 

 

 我们可以很明显的看到我们监听的 $route 对象被触发了,控制台也输出了;

下面我们来一起看一下嵌套路由:

 

  嵌套路由:

    很多时候我们的页面结构决定了我们可能需要嵌套路由,比如当我们进入主页之后有分类,然后当选择其中一个分类之后进入对应的详情,这个时候我们就可以用到嵌套路由;官方文档中给我们提供了一个 children 属性,这个属性是一个数组类型,里面实际放着一组路由;这个时候父子关系结构就出来了,所以 children 属性里面的是路由相对来说是 children 属性外部路由的子路由;

好记性不如烂代码,让我们通过代码来看一看:

  首先在我们的 src 目录下新建两个 vue 文件,分别是 phone.vue 和 computer.vue

  phone.vue

<template>
    <div>
        <p>{{msg}}</p>
    </div>
</template>
<script>
    export default {data () {
            return {
                msg: "嵌套手机组件"
            }
        }
    }
</script>

  computer.vue

<template>
    <div>
        <p>{{msg}}</p>
    </div>
</template>
<script>
    export default {data () {
            return {
                msg: "嵌套电脑组件"
            }
        }
    }
</script>

然后我们再修改我们的 App.vue 文件:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <div>
      <router-link to="/page1">Page1</router-link>
    </div>
    <router-view></router-view>
  </div>
</template>

<script>
export
default {
name:
'App'
}
</script>

<style>
#app {
font
-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text
-align: center;
color: #2c3e50;
margin
-top: 60px;
}
</style>

通过上面的 App.vue 文件我们可以看到,我们此时页面只有一个 page1 的标签了;

我们再来修改 router.js

import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter)
import page1  from './page1.vue';
import page2  from './page2.vue';
import user   from './user.vue';
import phone  from './phone.vue';
import computer from './computer.vue'

const routes=[
{
path:
'/page1',
component:page1,
children: [
{
path:
"phone",
component: phone
},
{
path:
"computer",
component: computer
},
]
},
// {path:"/page2",component:page2},
// // {path:'',redirect:"page1"}
// {path:"",component:page1},
// {path:"/user/:name",component:user}

]

const router=new VueRouter({
routes
});

export default router

为了大家看的直观点,其他路由全部注释了,页面只剩下 /page1 这一个路由了;

 

 

 

上面说到了,children 属性其实就是一个子路由集合,数组结构里面放着子路由;

效果图如下:

 

 

 路由导航两种方式:

  标签导航:标签导航 <router-link><router-link> 是通过转义为 <a></a> 标签进行跳转,其中 router-link 标签中的 to 属性会被转义为 a 标签中的 href 属性;

 

//跳转到名为 user 路由,并传递参数 userId
<router-link :to="{name:'user', params: { userId: 123}}">User</router-link>

 

 

 

  编程式导航:我们可以通过 this.$router.push() 这个方法来实现编程式导航,当然也可以实现参数传递,这种编程式导航一般是用于按钮点击之后跳转

router.push({name: 'user', params: { userId: 123}})

这两者都会把路由导航到 user/123 路径

命名路由:

  有的时候,通过一个名称来标识一个路由显得更方便一些,所以官方为了方便我们偷懒,又给我们在路由中添加了一个 name 属性,命名这个属性之后我们访问这个属性就等于直接访问到路由;

  普通路由:

router.push({path: '/user/:userId', params: { userId: 123}})

 

  命名路由:

router.push({name: 'user', params: { userId: 123}})

其实两者并没有什么区别,只是提供了两种方式来访问路由,可以通过路径来匹配也可以通过别名来匹配;

 

 

 

 今天的文章就到这里,下篇我们一起来学习 Vue 路由守卫!!!

加油!!