1. 理解

# 1. 理解

# 1.1. 说明

  1. 官方提供的用来实现SPA 的vue 插件
  2. github: https://github.com/vuejs/vue-router
  3. 中文文档: http://router.vuejs.org/zh-cn/
  4. 下载: npm install vue-router --save

# 1.2. 相关API 说明

  1. VueRouter(): 用于创建路由器的构建函数
new VueRouter({
// 多个配置项
})
  1. 路由配置
routes: [
	{ // 一般路由
		path: '/about',
		component: About
	},
	{ // 自动跳转路由
		path: '/',
		redirect: '/about'
	}
]
  1. 注册路由器
import router from './router'
new Vue({
	router
})
  1. 使用路由组件标签
  1. <router-link>: 用来生成路由链接
<router-link to="/xxx">Go to XXX</router-link>
  1. <router-view>: 用来显示当前路由组件界面
<router-view></router-view>

# 2. 基本路由

# 2.1. 效果

在这里插入图片描述

# 2.2. 路由组件

在这里插入图片描述 Home.vue About.vue

# 2.3. 应用组件: App.vue

<template>
  <div>
    <div class="row">
      <div class="col-xs-offset-2 col-xs-8">
        <div class="page-header"><h2>Router Test</h2></div>
      </div>
    </div>

    <div class="row">
      <div class="col-xs-2 col-xs-offset-2">
        <div class="list-group">
          <!--生成路由链接-->
          <router-link to="/about" class="list-group-item">About</router-link>
          <router-link to="/home" class="list-group-item">Home</router-link>
        </div>
      </div>
      <div class="col-xs-6">
        <div class="panel">
          <div class="panel-body">
            <!--显示当前组件-->
            <keep-alive>
              <router-view msg="abc"></router-view>
            </keep-alive>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

# 2.4. 路由器模块: src/router/index.js

import Vue from 'vue'
import Router from 'vue-router'

import About from '../pages/About'
import Home from '../pages/Home'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/about',
      component: About
    },
    {
      path: '/home',
      component: Home
    },
    {
      path: '/',
      component: About
    }
  ]
})

# 2.5. 注册路由器: main.js

import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({ // 配置对象的属性名都是一些确定的名称,不能随便修改
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

# 2.6. 优化路由器配置

linkActiveClass: 'active', // 指定选中的路由链接的class

# 2.7. 总结: 编写使用路由的3 步

  1. 定义路由组件
  2. 注册路由
  3. 使用路由
<router-link>
<router-view>

# 3. 嵌套路由

# 3.1. 效果

在这里插入图片描述

# 3.2. 子路由组件

在这里插入图片描述

# News.vue

<template>
  <ul>
    <li v-for="(news, index) in newsArr" :key="index">{{ news }}</li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      newsArr: ["news001", "news002", "news003", "news004"],
    };
  },
};
</script>

<style>
</style>

# Message.vue

<template>
  <ul>
    <li v-for="message in messages" :key="message.id">
      <a href="#">{{ message.title }}</a>
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      messages: [],
    };
  },
  mounted() {
    //模拟ajax请求从后台获取数据
    setTimeout(() => {
      const messages = [
        {
          id: 1,
          title: "message001",
        },
        {
          id: 2,
          title: "message002",
        },
        {
          id: 3,
          title: "message003",
        },
      ];
      this.messages = messages;
    }, 1000);
  },
};
</script>

<style>
</style>

# 3.3. 配置嵌套路由: src/router/index.js

import Vue from 'vue'
import Router from 'vue-router'

import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/about',
      component: About
    },
    {
      path: '/home',
      component: Home,
      children: [
        {
          // path: '/news' // path最左侧斜杠代表根路径
          path: '/home/news', //完整写法
          component: News
        },
        {
          path: 'message', // 简化写法
          component: Message
        },
        { //设置默认显示
          path: '',
          redirect: '/home/news'
        }
      ]
    },
    { //设置默认显示
      path: '/',
      redirect: '/about'
    }
  ]
})

# 3.4. 路由链接: Home.vue

<template>
  <div>
    <h2>Home</h2>
    <div>
      <ul class="nav nav-tabs">
        <li>
          <router-link to="/home/news">News</router-link>
          <router-link to="/home/message">Message</router-link>
        </li>
      </ul>

      <div>
        <router-view></router-view>
        <hr />
      </div>
    </div>
  </div>
</template>

<script>
export default {};
</script>

<style>
</style>

# 4. 向路由组件传递数据

# 4.1. 效果

# 4.2. 方式1: 路由路径携带参数(param/query)

  1. 配置路由
children: [
	{
	path: 'mdetail/:id',
	component: MessageDetail
	}
]
  1. 路由路径
<router-link :to="'/home/message/mdetail/'+m.id">{{m.title}}</router-link>
  1. 路由组件中读取请求参数
this.$route.params.id

# 4.3. 方式2: <router-view>属性携带数据

<router-view :msg="msg"></router-view>

然后组件用props接收

# 示例

# MessageDetail.vue

<template>
  <ul>
    <li>id: {{ messageDetail.id }}</li>
    <li>title: {{ messageDetail.title }}</li>
    <li>content: {{ messageDetail.content }}</li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      messageDetail: {
        id: "",
        title: "",
        content: "",
      },
    };
  },
  mounted() {
    setTimeout(() => {
      const allMessageDetails = [
        {
          id: 1,
          title: "message001",
          content: "message001 content...",
        },
        {
          id: 2,
          title: "message002",
          content: "message002 content...",
        },
        {
          id: 3,
          title: "message003",
          content: "message003 content...",
        },
      ];
      this.allMessageDetails = allMessageDetails;
      const id = this.$route.params.id * 1;
      this.messageDetail = allMessageDetails.find((detail) => detail.id === id);
    }, 1000);
  },
  watch: {
    $route: function(value){ // 路由路径(param)发生了改变
    const id = value.params.id * 1;
      this.messageDetail = this.allMessageDetails.find((detail) => detail.id === id);

    }
  }
};
</script>

<style>
</style>

# index.js

import Vue from 'vue'
import Router from 'vue-router'

import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import MessageDetail from '../pages/MessageDetail'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/about',
      component: About
    },
    {
      path: '/home',
      component: Home,
      children: [
        {
          // path: '/news' // path最左侧斜杠代表根路径
          path: '/home/news', //完整写法
          component: News
        },
        {
          path: 'message', // 简化写法
          component: Message,
          children: [
            {
              path: '/home/message/detail/:id',
              component: MessageDetail
            }
          ]
        },
        { //设置默认显示
          path: '',
          redirect: '/home/news'
        }
      ]
    },
    { //设置默认显示
      path: '/',
      redirect: '/about'
    }
  ]
})

# 5. 缓存路由组件对象

# 5.1. 理解

  1. 默认情况下, 被切换的路由组件对象会死亡释放, 再次回来时是重新创建的
  2. 如果可以缓存路由组件对象, 可以提高用户体验

# 5.2. 编码实现

<keep-alive>
	<router-view></router-view>
</keep-alive>

# 6. 编程式路由导航

# 6.1. 效果

在这里插入图片描述

# 6.2. 相关API

  1. this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
  2. this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
  3. this.$router.back(): 请求(返回)上一个记录路由
  4. this.$router.go(-1): 请求(返回)上一个记录路由
  5. this.$router.go(1): 请求下一个记录路由

# 示例

# Message.vue

<template>
  <div>
    <ul>
      <li v-for="message in messages" :key="message.id">
        <!-- <a href="#">{{ message.title }}</a> -->
        <router-link :to="`/home/message/detail/${message.id}`">{{
          message.title
        }}</router-link>
        <button @click="pushShow(message.id)">push查看</button>
        <button @click="replaceShow(message.id)">replace查看</button>
      </li>
    </ul>
    <button @click="$router.back()">回退</button>
    <hr />
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  data() {
    return {
      messages: [],
    };
  },
  methods: {
    pushShow(id) {
      this.$router.push(`/home/message/detail/${id}`);
    },
    replaceShow(id) {
      this.$router.replace(`/home/message/detail/${id}`);
    },
  },
  mounted() {
    //模拟ajax请求从后台获取数据
    setTimeout(() => {
      const messages = [
        {
          id: 1,
          title: "message001",
        },
        {
          id: 2,
          title: "message002",
        },
        {
          id: 3,
          title: "message003",
        },
      ];
      this.messages = messages;
    }, 1000);
  },
};
</script>

<style>
</style>

# 总结

# 路由

  1. 理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
  2. 前端路由:key是路径,value是组件。

# 1.基本使用

  1. 安装vue-router,命令:npm i vue-router

  2. 应用插件:Vue.use(VueRouter)

  3. 编写router配置项:

   //引入VueRouter
   import VueRouter from 'vue-router'
   //引入Luyou 组件
   import About from '../components/About'
   import Home from '../components/Home'
   
   //创建router实例对象,去管理一组一组的路由规则
   const router = new VueRouter({
   	routes:[
   		{
   			path:'/about',
   			component:About
   		},
   		{
   			path:'/home',
   			component:Home
   		}
   	]
   })
   
   //暴露router
   export default router
  1. 实现切换(active-class可配置高亮样式)
   <router-link active-class="active" to="/about">About</router-link>
  1. 指定展示位置
  <router-view></router-view>

# 2.几个注意点

  1. 路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。
  2. 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
  3. 每个组件都有自己的$route属性,里面存储着自己的路由信息。
  4. 整个应用只有一个router,可以通过组件的$router属性获取到。

# 3.多级路由(多级路由)

  1. 配置路由规则,使用children配置项:
   routes:[
   	{
   		path:'/about',
   		component:About,
   	},
   	{
   		path:'/home',
   		component:Home,
   		children:[ //通过children配置子级路由
   			{
   				path:'news', //此处一定不要写:/news
   				component:News
   			},
   			{
   				path:'message',//此处一定不要写:/message
   				component:Message
   			}
   		]
   	}
   ]
  1. 跳转(要写完整路径):
   <router-link to="/home/news">News</router-link>

# 4.路由的query参数

  1. 传递参数
   <!-- 跳转并携带query参数,to的字符串写法 -->
   <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
   				
   <!-- 跳转并携带query参数,to的对象写法 -->
   <router-link 
   	:to="{
   		path:'/home/message/detail',
   		query:{
   		   id:666,
               title:'你好'
   		}
   	}"
   >跳转</router-link>
  1. 接收参数:
   $route.query.id
   $route.query.title

# 5.命名路由

  1. 作用:可以简化路由的跳转。

  2. 如何使用

    1. 给路由命名:
      {
      	path:'/demo',
      	component:Demo,
      	children:[
      		{
      			path:'test',
      			component:Test,
      			children:[
      				{
                            name:'hello' //给路由命名
      					path:'welcome',
      					component:Hello,
      				}
      			]
      		}
      	]
      }
  1. 简化跳转:
      <!--简化前,需要写完整的路径 -->
      <router-link to="/demo/test/welcome">跳转</router-link>
      
      <!--简化后,直接通过名字跳转 -->
      <router-link :to="{name:'hello'}">跳转</router-link>
      
      <!--简化写法配合传递参数 -->
      <router-link 
      	:to="{
      		name:'hello',
      		query:{
      		   id:666,
                  title:'你好'
      		}
      	}"
      >跳转</router-link>

# 6.路由的params参数

  1. 配置路由,声明接收params参数
   {
   	path:'/home',
   	component:Home,
   	children:[
   		{
   			path:'news',
   			component:News
   		},
   		{
   			component:Message,
   			children:[
   				{
   					name:'xiangqing',
   					path:'detail/:id/:title', //使用占位符声明接收params参数
   					component:Detail
   				}
   			]
   		}
   	]
   }
  1. 传递参数
   <!-- 跳转并携带params参数,to的字符串写法 -->
   <router-link :to="/home/message/detail/666/你好">跳转</router-link>
   				
   <!-- 跳转并携带params参数,to的对象写法 -->
   <router-link 
   	:to="{
   		name:'xiangqing',
   		params:{
   		   id:666,
               title:'你好'
   		}
   	}"
   >跳转</router-link>

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

  1. 接收参数:
   $route.params.id
   $route.params.title

# 7.路由的props配置

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

{
	name:'xiangqing',
	path:'detail/:id',
	component:Detail,

	//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
	// props:{a:900}

	//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
	// props:true
	
	//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
	props(route){
		return {
			id:route.query.id,
			title:route.query.title
		}
	}
}
  1. 作用:控制路由跳转时操作浏览器历史记录的模式
  2. 浏览器的历史记录有两种写入方式:分别为pushreplacepush是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
  3. 如何开启replace模式:<router-link replace .......>News</router-link>

# 9.编程式路由导航

  1. 作用:不借助<router-link>实现路由跳转,让路由跳转更加灵活

  2. 具体编码:

   //$router的两个API
   this.$router.push({
   	name:'xiangqing',
   		params:{
   			id:xxx,
   			title:xxx
   		}
   })
   
   this.$router.replace({
   	name:'xiangqing',
   		params:{
   			id:xxx,
   			title:xxx
   		}
   })
   this.$router.forward() //前进
   this.$router.back() //后退
   this.$router.go() //可前进也可后退

# 10.缓存路由组件

  1. 作用:让不展示的路由组件保持挂载,不被销毁。

  2. 具体编码:

   <keep-alive include="News"> 
       <router-view></router-view>
   </keep-alive>

# 11.两个新的生命周期钩子

  1. 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
  2. 具体名字:
    1. activated路由组件被激活时触发。
    2. deactivated路由组件失活时触发。

# 12.路由守卫

  1. 作用:对路由进行权限控制

  2. 分类:全局守卫、独享守卫、组件内守卫

  3. 全局守卫:

   //全局前置守卫:初始化时执行、每次路由切换前执行
   router.beforeEach((to,from,next)=>{
   	console.log('beforeEach',to,from)
   	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
   		if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则
   			next() //放行
   		}else{
   			alert('暂无权限查看')
   			// next({name:'guanyu'})
   		}
   	}else{
   		next() //放行
   	}
   })
   
   //全局后置守卫:初始化时执行、每次路由切换后执行
   router.afterEach((to,from)=>{
   	console.log('afterEach',to,from)
   	if(to.meta.title){ 
   		document.title = to.meta.title //修改网页的title
   	}else{
   		document.title = 'vue_test'
   	}
   })
  1. 独享守卫:
   beforeEnter(to,from,next){
   	console.log('beforeEnter',to,from)
   	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
   		if(localStorage.getItem('school') === 'atguigu'){
   			next()
   		}else{
   			alert('暂无权限查看')
   			// next({name:'guanyu'})
   		}
   	}else{
   		next()
   	}
   }
  1. 组件内守卫:
   //进入守卫:通过路由规则,进入该组件时被调用
   beforeRouteEnter (to, from, next) {
   },
   //离开守卫:通过路由规则,离开该组件时被调用
   beforeRouteLeave (to, from, next) {
   }

# 13.路由器的两种工作模式

  1. 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
  2. hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
  3. hash模式:
    1. 地址中永远带着#号,不美观 。
    2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
    3. 兼容性较好。
  4. history模式:
    1. 地址干净,美观 。
    2. 兼容性和hash模式相比略差。
    3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
上次更新: 2022/4/13 12:52:30