• vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。
  • 路由用于设定访问路径, 将路径和组件映射起来.
  • 在vue-router的单页面应用中, 页面的路径的改变就是组件的切换.
  • https://router.vuejs.org/zh/

(一) 基本使用

[1]. 安装vue-router

npm install vue-router --save

[2]. 新建映射的组件

在src\components目录下新建Home.vue和About.vue文件,并在template里边输入内容。
如Home.vue文件中的内容:

<template>
  <div>
    <p>这里是Home.vue</p>
  </div>
</template>

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

[3]. 引入组件并和路径对应

  1. 新建\src\router文件夹,并在文件夹下新建index.js文件

  2. 引入router插件并注册,引入刚创建的两个组件文件

  3. 创建VueRouter对象,使路径和组件对应。

    import Vue from "vue";
    import Router from "vue-router"; //引入router
    Vue.use(VueRouter);//注册router
    
    //下面引入方式等价,这里的@ 等于/src
    import Home from '../components/Home' //引入组件Home
    import About from '@/components/About'
    
    export default new Router({
      routes: [
        {
          path: '/home',
          name: 'Home', //name属性,这里和组件中至少要有一处有该属性
          component: Home
        },
        {
          path: '/about',
          name: 'About',
          component: About
        }
      ]
    })
    
  • 在main.js文件中引入路由文件

    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'; //引入路由文件
    Vue.config.productionTip = false
    
    new Vue({
      router,//使用
      render: h => h(App),
    }).$mount('#app')
    

[4]. 显示组件

在src/app.vue中添加

<template>
  <div id="app">
	   <router-link to="/home">首页</router-link>
	   <router-link to="/about">关于</router-link>
	  <router-view></router-view>
  </div>
</template>
  • <router-link>: 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个<a>标签.
  • <router-view>: 该标签会根据当前的路径, 动态渲染出不同的组件.
  • 网页的其他内容, 比如顶部的标题/导航, 或者底部的一些版权信息等会和<router-view>处于同一个等级.
  • 在路由切换时, 切换的是挂载的组件, 其他内容不会发生改变.

[5].设置默认路径

在路由映射文件中 ( router/index.js),redirect属性是重定向,即当路径为空时(path也可以设置为" path: ‘/’ "),将页面重定向到home组件上。

export default new Router({
  routes: [
    {
      path: '',
      redirect: '/home'
    },
	....
  ]
})

[6].将hash模式换为history模式

当前的路径为下图,希望改为:“localhost:8080/home”形式
在这里插入图片描述
在路由映射文件router/index.js中的VueRouter对象添加,mode属性即可。

export default new Router({
  routes: [...],
  mode: 'history'
})

[7]. router-link补充

  1. 在前面的<router-link>中, 我们只是使用了一个属性:to, 用于指定跳转的路径。

  2. tag: tag可以指定<router-link>之后渲染成什么组件

    <router-link to='/home' tag='li'>Home</router-link>
    

    上面的代码会被渲染成一个<li>元素, 而不是<a>

  3. replace: replace替换掉(浏览历史)栈中的最上边的历史记录。

    <router-link to='/home' replace>Home</router-link>
    
  4. active-class: 当<router-link>对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称。

    • 在进行高亮显示的导航菜单或者底部tabbar时, 会使用到该类。

    • 但是通常不会修改类的属性, 会直接使用默认的router-link-active即可。

    • 在路由映射文件router/index.js中,可以添加linkActiveClass属性,来统一管理当控件选中是的样式

      export default new Router({
      	.....
        linkActiveClass: 'active'
      })
      

[8]. 利用 路由信息对象$router 实现跳转

路由信息对象:每个组件会被注入$router,可以利用它进行一些信息的获取。

  • router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。

在/src/app.vue主组件文件中,利用方法实现跳转。

<template>
  <div id="app">
   <button @click="goHome()">首页</button>
   <button @click="goAbout()">关于</button>
  <router-view></router-view>
  </div>
</template>

<script>
  export default{
    name: 'App',
    methods: {
      goHome(){
      	//字符串
        this.$router.push('/home');
        // 对象 
		//router.push({ path: 'home' })
		// 命名的路由 /user/123  这里的name是routes中的name
		//router.push({ name: 'user', params: { userId: '123' }})
		// 带查询参数,变成 /register?plan=private
		//router.push({ path: 'register', query: { plan: 'private' }})
      },
      goAbout(){
        this.$router.push('/about');
      }
    }
  }
</script>

(二) 动态路由匹配(参数传递)

[1]. query的类型:

  • 传递的方式: 组件中使用query的key作为传递方式
  • 传递后形成的路径: /router?id=123, /router?id=abc
  1. 在路由入口函数中引入和写入对应的路由关系。
    home.vue中添加:
    <!-- 点击消息后url为:'/home/news?name=message&id=001' -->
    <router-link :to="{path:'/home/message', query: {name:'message', id: '001'}}">消息</router-link>
    
  2. 组件中获取query参数
    在HomeMessage.vue中获取传递的参数
    <template>
    	<div>
    	  <p>这里是HomeMessage.vue</p>
    	  <p>{{$route.query.name}}</p>
    	  <p>{{getQueryId}}</p>
    	</div>
    </template>
    
    <script>
    export default {
    	name: 'HomeMessage',
    	computed:{
    	  getQueryId(){
    	    return this.$route.query.id;
    	  }
    	}
    }
    </script>
    

[2]. params的类型:

注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!

  1. 配置路由,声明接受params参数
    在路由配置文件中router/index.js

    import Vue from 'vue';
    import Router from 'vue-router';
    
    Vue.use(Router);
    import Info from '@/components/Info'
    
    export default new Router({
      routes:[
        {
         name: 'xinxi', //如果使用to的对象写法则需要添加该属性
          path: '/info/:id/:name',//使用占位符声明接收的params参数的key
          component: Info
        }
      ]
    });
    
  2. 传递参数
    App.vue文件

    <template>
      <div id="app">
       <!-- 跳转到info页面时携带 id为123,name为tom -->
       <!-- 跳转并携带params参数,to的字符串写法 -->
        <router-link to="/info/123/tom">信息</router-link>
         <!-- 跳转并携带params参数,to的对象写法, 这里的name必须和路由配置项中的name对应 -->
         <router-link
          :to="{
            name: 'xinxi', 
            params: {
              id: 123,
              name: 'tom',
            },
          }">信息</router-link>
         
        <router-view></router-view>
      </div>
    </template>
    
  3. 接受参数的组件

    <template>
      <div>
        <p>这里是Info.vue</p>
         <p>我的姓名:{{$route.params.name}},我的ID:{{getId}}</p>
      </div>
    </template>
    
    <script>
    export default {
      name:'Info',
      computed:{
        getId(){
          return this.$route.params.id
        }
      }
    }
    </script>
    

[3]. 路由的props配置

作用:让路由组件更方便的收到参数

  1. 路由配置文件router/index.js
    import Vue from 'vue';
    import Router from 'vue-router';
    Vue.use(Router);
    import Detail from '@/components/Detail'
    export default new Router({
      routes:[
        {
          path: '/detail', //第一、三种写法需用到
          // path: '/detail/:id/:title', //第二种写法需用到
          component: Detail,
          //第一种写法: props值为对象,该对象所有的key-value的组合最终都会通过props传给组件
          // props: {id: 13, title: '这是详情的标题'},.
          //第二种写法: props值为true,则把路由接收到的所有params参数通过props传给Detail组件
          // props: true,
          //第三种写法: props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
          props(route){
            console.log(route);
            return{
              id: route.query.id,
              title: route.query.title
            }
          }
        }
      ]
    });
    
  2. Detail.vue组件中配置
    <template>
      <div>
        <p>这里是Detail.vue</p>
        <p>id是:{{id}}, 标题是:{{title}}</p>
      </div>
    </template>
    
    <script>
    export default {
      name: 'Detail',
      props:['id', 'title']
    }
    </script>
    
  3. App.vue组件中改变url和传递参数
<template>
  <div id="app">
      <!-- 第一种写法用到 -->
      <!--<router-link to="/detail?id=123&title=asdf">详情</router-link> -->
      <!-- 第二种写法用到 -->
      <!-- <router-link to="/detail/123/asdf">详情</router-link> -->
      <!-- 第三种写法用到 -->
      <router-link to="/detail?id=123&title=asdf">详情</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
	export default {
	  name: "App",
	};
</script>

(三) 路由嵌套

[1]. 路由嵌套

嵌套路由是一个很常见的功能

  • 比如在home页面中, 我们希望通过/home/news和/home/message访问一些内容.
  • 一个路径映射一个组件, 访问这两个路径也会分别渲染两个组件.
  1. 在/src/components组件文件夹中新建HomeNews.vue组件和HomeMessage.vue组件
    HomeNews内容如下:

    <template>
      <div>
        <p>这里是HomeNews.vue</p>
      </div>
    </template>
    
    <script>
    export default {
      name: "HomeNew",
    };
    </script>
    
  2. 在路由配置文件src/router/index.js中引入这两个文件

    const HomeNews = ()=>import('../components/HomeNews');
    const HomeNews = ()=>import('../components/Message');
    ...
    export default new Router({
      routes: [
        ...
        {
          path: '/home',
          name: 'Home',
          component: Home,
          children: [
              {
                path: '',
                redirect: 'news'	//这里没有斜线 '/'
              },
              {
                path: 'news', //这里没有斜线 '/'
                name: 'News',
                component: HomeNews
              },
              {
                path: 'message',
                name: 'Message',
                component: HomeMessage
              }
          ]
        },
        ...
    })
    
  3. 在Home.vue组件中添加

    <template>
     <div>
       <p>这里是Home.vue</p>
       <router-link to="/home/news">新闻</router-link>
       <router-link to="/home/message">消息</router-link>
       <router-view></router-view>
     </div>
    </template>
    
    <script>
    export default {
     name: 'Home'
    };
    </script>
    
  4. 在本地服务器运行。

[2]. 命名路由

当url路径越来越长时,可以使用命名路由来简化路径。

  1. 如果想要查看 HomeNewsItem 组件的内容,写需要很长的路径,可以使用命名路由
 <div>
    <p>这里是HomeNews.vue</p>
    <!-- 普通写法 -->
    <router-link to="/home/news/item">新闻item</router-link>
     <!-- 命名路由-->
    <router-link :to="{name: 'new_item'}">新闻item</router-link>
    <router-view></router-view>
  </div>
//router/index.js中路由配置
export default new Router({
 routes:[
   {
     path: '/home',
     component: Home,
     children:[
       {
         path: 'news',
         component: HomeNews,
         children: [
           {
             name: 'new_item',
             path: 'item',
             component: HomeNewsItem
           }
         ]
       }
     ]
   },
 ]
});

(四)缓存路由组件:keep-alive

  • keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染(如果没有keep-alive组件是会被销毁和重新创建,添加keep-alive是不会被销毁的)。

  • router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存

  • 当data中的数据改变时,组件里的变量也会相应的改变。

  • keep-alive实例:

    <div id="app">
        <button @click="currentCpn=1">btn1</button>
        <button @click="currentCpn=2">btn2</button>
        <button @click="currentCpn=3">btn3</button>
        <!-- 可以看看去掉keep-alive的效果 -->
        <keep-alive>
            <cpn v-if="currentCpn === 1"></cpn>
            <cpn2 v-if="currentCpn === 2"></cpn2>
            <cpn3 v-if="currentCpn === 3"></cpn3>
        </keep-alive>
    </div>
    
    <template id="cpn">
        <p>{{name}}</p>
    </template>
    
    <template id="cpn2">
        <p>cpn2</p>
    </template>
    
    <template id="cpn3">
        <p>cpn3</p>
    </template>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const cpn = {
            template: "#cpn",
            data(){
                return{
                    name:"cpn" //可以实现响应式改变
                }
            },
            mounted() {
                console.log('cpn mounted');
            },
            destroyed() {
                console.log('cpn destroyed');
            }
        }
    
        const cpn2 = {
            template: "#cpn2",
            mounted() {
                console.log('cpn2 mounted');
            },
            destroyed() {
                console.log('cpn2 destroyed');
            }
        }
    
        const cpn3 = {
            template: "#cpn3",
            mounted() {
                console.log('cpn3 mounted');
            },
            destroyed() {
                console.log('cpn3 destroyed');
            }
        }
    
        const app = new Vue({
            el: "#app",
            data: {
                currentCpn: 1
            },
            components: {
                cpn,
                cpn2,
                cpn3
            }
        });
    </script>
    

[1]. include 和 exclude

  • include - 字符串或正则表达,只有匹配的组件会被缓存

    <!-- Detail是组件的name属性的值 -->
    <!-- 缓存多个 可以使用 :include="['News', 'Detail']" -->
    <keep-alive include="Detail"> 
    	<router-view></router-view>
    </keep-alive>
    
  • exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
    匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配。

    <!-- 不缓存Detail(组件的name的值) -->
    <keep-alive exclude="Detail"> 
      <router-view></router-view>
    </keep-alive>
    
    //Detail 组件
    export default {
        name:"Detail",  //与上面的对应
    }
    

[2]. activated 和 deactivated 生命周期钩子

  • 当组件在<keep-alive> 内被切换,它的 activateddeactivated 这两个生命周期钩子函数将会被对应执行。
  • 在 2.2.0 及其更高版本中,activateddeactivated 将会在 <keep-alive> 树内的所有嵌套组件中触发。

(五).注意点和 $router和$route

  1. 路由组件通常存放在src\pages文件夹中(自己创建),一般组件通常存放在components文件夹中。
  2. 通过切换,“隐藏” 的路由组件默认是被销毁掉的,需要的时候再去挂载。
  3. $router是VueRouter的一个对象,通过Vue.use(VueRouter)和Vue构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由,包含了许多关键的对象和属性。
  4. $route是一个跳转的路由对象,每一个组件都会有一个$route对象,是一个局部的对象,可以获取对应的name,path,params,query等
  5. $router$route 在组件实例上可以看到。

(六) 路由守卫

  • vue-router提供的导航守卫主要用来监听监听路由的进入和离开的.

  • vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发.

  • 参数或查询的改变并不会触发进入/离开的导航守卫。

  • 主要包括beforeEach(to, from, next) 和 afterEach(to, from)
    beforeEach(to, from, next) – 初始化和路由切换之前被调用
    to : router即将进入的路由对象
    from : 当前导航即将离开的路由
    next : Function,进行管道中的一个钩子,如果执行完了,则导航的状态就是 confirmed (确认的);否则为false,终止导航。

    afterEach(to, from)–初始化和路由切换之后被调用

  • 这类钩子主要作用于全局,一般用来判断权限,以及以及页面丢失时候需要执行的操作

    https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E8%B7%AF%E7%94%B1%E7%8B%AC%E4%BA%AB%E7%9A%84%E5%AE%88%E5%8D%AB

[1]. 全局守卫

  1. 在路由配置文件router/index.js文件中, 定义的路由映射中,有一个属性meta,在其中添加一个title信息

    const router = new VueRouter({
    	routes: [
    		{
    	      path:'/profile',
    	      name: 'Profile',
    	      component: Profile,
    	      meta:{ //路由元信息,用户自己可以定义其中数据的类型
    	        title:'档案' // title是自己定义的
    	      },
    	    }
    	]
    })
    
  2. 通过beforeEach钩子函数当路由改变之前调用该方法来修改页面的title

    //全局前置路由守卫--初始化和每次路由切换之前被调用
    router.beforeEach((to, from, next)=>{
    	  window.document.title = to.matched[0].meta.title;
    	  next();
    });
    

[2]. 独享路由守卫

如果你不想全局配置守卫的话,你可以为某些路由单独配置守卫

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => { //只有这一个独享路由守卫
        // 参数用法什么的都一样,调用顺序在全局前置守卫后面,所以不会被全局守卫覆盖
        // ...
      }
    }
  ]
})

[3]. 组件内的路由守卫

  • beforeRouteEnter(to, from, next) 通过路由规则,进入该组件时被调用。不能获取组件实例 this,组件实例还没被创建

  • beforeRouteUpdate (2.2) 路由复用同一个组件时, 在当前路由改变,但是该组件被复用时调用 可以访问组件实例 this

  • beforeRouteLeave(to, from, next) 通过路由规则,离开该组件时被调用。可以访问组件实例 this

    export default {
      name:'Info',
      computed:{
        getId(){
          console.log('$route', this.$route);
        }
      },
      beforeRouteEnter (to, from, next) {
        console.log('进入Info.vue组件中');
        console.log(this);   //undefined
        console.log(to);  //该页面 等于 $route
        console.log(from); //从哪个页面来的
    
        next();
      },
      beforeRouteLeave (to, from, next) {
        console.log('离开Info.vue组件中');
        console.log(this);
        console.log(to);  //要去哪个页面
        console.log(from);//该页面 等于 $route
    
        next()
      }
    }
    

(七) 路由懒加载

  • 首先, 我们知道路由中通常会定义很多不同的页面.

  • 这个页面最后被打包在哪里呢? 一般情况下, 是放在同一个js文件中.

  • 但是, 页面这么多放在一个js文件中, 必然会造成这个页面非常的大.

  • 如果我们一次性从服务器请求下来这个页面, 可能需要花费一定的时间, 甚至用户的电脑上还出现了短暂空白的情况.

  • 如何避免这种情况呢? 使用路由懒加载就可以了.

  • 按照如下方式修改路由入口文件router/index.js文件

    方式一: 结合Vue的异步组件和Webpack的代码分析.

    const Home = resolve => { require.ensure(['../components/Home.vue'], () => { resolve(require('../components/Home.vue')) })};
    

    方式二: AMD写法

    const About = resolve => require(['../components/About.vue'], resolve);
    

    方式三: 在ES6中, 我们可以有更加简单的写法来组织Vue异步组件和Webpack的代码分割.

    const Home = () => import('../components/Home.vue');
    
    export default new Router({
      routes: [
    	    {
    	      path: '/home',
    	      name: 'Home',
    	      component: Home
    	    }
        ]
    })
    

[2].把组件按组分块

有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。

const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')

Webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。

(八) 捕获所有路由或404 Not found路由

  • 常规参数只会匹配被 / 分隔的 URL 片段中的字符。如果想匹配任意路径,我们可以使用通配符 (*):

    {
      // 会匹配所有路径
      path: '*'
    }
    {
      // 会匹配以 `/user-` 开头的任意路径
      path: '/user-*'
    }
    
  • 当使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。路由 { path: ‘*’ } 通常用于客户端 404 错误。如果你使用了History 模式,请确保正确配置你的服务器。

  • 当使用一个通配符时,$route.params 内会自动添加一个名为 pathMatch 参数。它包含了 URL 通过通配符被匹配的部分:

    // 给出一个路由 { path: '/user-*' }
    this.$router.push('/user-admin')
    this.$route.params.pathMatch // 'admin'
    // 给出一个路由 { path: '*' }
    this.$router.push('/non-existing')
    this.$route.params.pathMatch // '/non-existing'
    
Logo

前往低代码交流专区

更多推荐