路由

  • 概念: 一组key-value对应关系
key1 + value1 => 路由route
key2 + value2 => 路由route
......

- 上述路由的集合,就是'路由器'(router)

- key为路径,value对应 组件或者 回调func
  • 插件: vue-router,作路由跳转(专门实现SPA应用)

  • SPA应用

- 单页web应用(single page web application,SPA)

- 整个应用只有一个完整的页面

- 点击页面中的导航链接不会刷新页面,只会作页面的局部更新

- 数据需要通过ajax请求获取
  • vue-router安装/引入
npm i vue-router@3 // 安装和vue2版本相匹配的router版本

### main.js
......
import VueRouter from 'vue-router' // 引入

Vue.use(VueRouter) // 使用

new Vue({
  render: h => h(App),
}).$mount('#app')

  • demo演示:路由实现两个页面的切换,但是页面不刷新,只更新页面部分内容
### About组件
<template>
	<div>
		<h1>我是About组件的内容</h1>
	</div>
</template>

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

### Home组件
<template>
	<div>
		<h1>我是Home组件的内容</h1>
	</div>
</template>

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

### router(src目录底下新建该目录)
### router/index.js
import VueRouter from 'vue-router' // 引入router对象

import About from '../components/Router/About.vue' // 引入两个组件
import Home from '../components/Router/Home.vue'

export default new VueRouter({ // 实例化
	routes:[ // 配置路由
		{
			path:'/about', // 配置路径
			component:About // 注册组件
		},
		{
			path:'/home',
			component:Home
		},
	]
})

### main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'

import router from './router' // 导入router对象

Vue.use(VueRouter)

new Vue({
  render: h => h(App),
  router:router // 配置
}).$mount('#app')

### app.vue(使用bootstrap框架)
<template>
  <div>
    <div class="row">
      <div class="col-xs-offset-2 col-xs-8">
        <div class="page-header"><h2>Vue Router Demo</h2></div>
      </div>
    </div>
    <div class="row">
      <div class="col-xs-2 col-xs-offset-2">
        <div class="list-group">
		  <!-- 原始html中我们使用a标签实现页面的跳转,页面会跳动 -->
          <!-- <a class="list-group-item active" href="./about.html">About</a> -->
          <!-- <a class="list-group-item" href="./home.html">Home</a> -->

		  <!-- Vue中借助router-link标签实现路由的切换(本质的渲染还是变回<a>标签) -->
		  <router-link class="list-group-item" active-class="active" to="/about">About</router-link>
          <router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
        </div>
      </div>
      <div class="col-xs-6">
        <div class="panel">
          <div class="panel-body">
				<!-- 指定组件的呈现位置 -->
            <router-view></router-view>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

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

- 小结:
	- 使用<router-link>来指定path
		- 单单指定 <router-link> 只实现了url路径跳转,组件内容并不会被呈现出来
		
	- 使用<router-view>来指定组件呈现的位置
	

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
    
  4. 实现切换(active-class可配置高亮样式)

    <router-link active-class="active" to="/about">About</router-link>
    
  5. 指定展示位置

    <router-view></router-view>
    

路由组件和一般组件

  • 上述示例的 About和Home就是路由组件,一般是写在pages.其他组件就是一般组件
- 把上述demo组件作一下分类

- src目录下,新建'pages'目录,把'About.vue'和'Home.vue'丢里面

- router.index.js的组件引入方式修改一下(其他方式不变即可)
	
	......
	import About from '../pages/About.vue'
	import Home from '../pages/Home.vue'

几个注意点

\1. 路由组件通常存放在```pages```文件夹,一般组件通常存放在```components```文件夹。

\2. 通过切换,“隐藏”了的路由组件,默认是被销毁掉的(beforeCreate可以验证),需要的时候再去挂载

\3. 每个组件都有自己的```$route```属性,里面存储着自己的路由信息(每个路由组件的$route都不一样)

\4. 整个应用只有一个router,可以通过组件的```$router```属性获取到(每个路由组件的$router都一样)

多级路由demo演示(Home组件新增两个导航链接,分别展示News组件信息和Message组件信息)

### pages.News.vue
<template>
	<ul>
		<li>news001</li>
		<li>news002</li>
		<li>news003</li>
	</ul>
</template>

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

### pages.Message.vue
<template>
	<div>
		<ul>
			<li>
				<a href="/message1">message001</a>&nbsp;&nbsp;
			</li>
			<li>
				<a href="/message2">message002</a>&nbsp;&nbsp;
			</li>
			<li>
				<a href="/message/3">message003</a>&nbsp;&nbsp;
			</li>
		</ul>
	</div>
</template>

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

### index.js
import VueRouter from 'vue-router'
......
import Home from '../pages/Home.vue'
import Message from '../pages/Message.vue' // 引入
import News from '../pages/News.vue' // 引入


export default new VueRouter({
	routes:[
		{
			path:'/about',
			component:About
		},
		{
			path:'/home',
			component:Home,
			children:[ // 子路由使用children配置项
				{
					path:'message', // 不能写成'/message',即不能加'/',源码底层自动加了
					component:Message
				},
				{
					path:'news',
					component:News
				}
			]
		},
	]
})

### Home.vue
<template>
	<div>
		<h1>我是Home组件的内容</h1>
		<div>
			<ul class="nav nav-tabs">
				<li> <!--路由,to="/home/news"一定要带上home,才表示子路由-->
					<router-link class="list-group-item" active-class="active" to="/home/news">News</router-link>
				</li>
				<li>
					<router-link class="list-group-item" active-class="active" to="/home/message">Message</router-link>
				</li>
			</ul>
			<router-view></router-view> <!--组件要展示的位置-->
		</div>
	</div>
</template>

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

多级路由(也叫嵌套路由)小结

- 配置路由规则,使用children配置项

	......
	routes:[
		{
			path:'/about',
			component:About
		},
		{
			path:'/home',
			component:Home,
			children:[ // 新增配置项
				{
					path:'message', // 不要写成'/message'
					component:Message
				},
				{
					path:'news',
					component:News
				}
			]
		},
	]
	
- 跳转要写完整路径
	// to="/home/news"
	<router-link class="list-group-item" active-class="active" to="/home/news">News</router-link>

query参数使用

  • 作用: 用于url路径中传参
  • 演示demo(Message组件再嵌套一个Detail组件,展示消息编号和标题)
### Detail.vue
<template>
	<ul>
		<!--通过$route.query.xxx获取url路径传参-->
		<li>消息编号: {{$route.query.id}}</li>
		<li>消息内容: {{$route.query.title}}</li>
	</ul>
</template>

<script>
	export default {
		name:'Detail'
	}
</script>
......

### index.js
import VueRouter from 'vue-router'
......
import Detail from '../pages/Detail.vue'

export default new VueRouter({
	routes:[
		{
			path:'/about',
			......
		},
		{
			path:'/home',
			......
			children:[
				......
				{
					path:'message',
					component:Message,
					children:[
						{
							path:'detail', // Detail路径
							component:Detail
						}
					]
				},
			]
		},
	]
})

### Message.vue
<template>
	<div>
		<ul>
			<li v-for="message in messageList" :key="message.id">
				<!-- <a href="/message1">{{message.title}}</a>&nbsp;&nbsp; -->
				<!--要写成Js表达式形式,所以':to';值要使用``包裹起来,并使用${}传值-->
				<router-link :to="`/home/message/detail?id=${message.id}&title=${message.title}`">{{message.title}}</router-link>&nbsp;&nbsp;
			</li>
		</ul>
		<hr >
		<router-view></router-view>
		
	</div>
</template>

<script>
	export default {
		name:'Message',
		data(){
			return {
				messageList:[ // 数据不再写死,而是用这种方式
					{id:'001',title:'1号消息'},
					{id:'002',title:'2号消息'},
					{id:'003',title:'3号消息'},
				]
			}
		},
	}
</script>
  • 上述示例演示的是 query的字符串写法,现在演示 query的对象写法
......
<router-link :to="{path:'/home/message/detail',query:{id:message.id,title:message.title}}">{{message.title}}</router-link>&nbsp;&nbsp;
......

- 对象式这种写法,之前about的路径可以这么写

 <!-- <router-link class="list-group-item" active-class="active" to="/about">About</router-link> -->
 															<!--对象式写法-->
 <router-link class="list-group-item" active-class="active" :to="{path:'/about'}">About</router-link>

路由的query参数

- 传递参数:
   <!-- 跳转并携带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>

- 接收参数:
   $route.query.id
   $route.query.title

命名路由: 给路由取个名字,代替path选项

  • 作用: 当path路径很长的时候,书写不方法,就可以使用'命名路由'代替path配置项,从而简化代码
### index.js
import VueRouter from 'vue-router'
......

export default new VueRouter({
	routes:[
		{	
			name:'guanYu', // 新增name配置项
			path:'/about',
			component:About
		},
		{
			path:'/home',
			......
			children:[
				{
					path:'news',
					......
				},
				{
					path:'message',
					......
					children:[
						{	
							name:'xiangQing', // 新增name配置项
							path:'detail',
							component:Detail
						}
					]
				},
			]
		},
	]
})

### App.vue
......
<div class="list-group">
		
    <!-- <router-link class="list-group-item" active-class="active" :to="{path:'/about'}">About</router-link> -->
    <!--使用name取代path-->
    <router-link class="list-group-item" active-class="active" :to="{name:'guanYu'}">About</router-link>
    <router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
</div>

### Message.vue
......
<li v-for="message in messageList" :key="message.id">
				<!-- <router-link :to="{path:'/home/message/detail',query:{id:message.id,title:message.title}}">{{message.title}}</router-link>&nbsp;&nbsp; -->
							<!--使用name取代path-->
				<router-link :to="{name:'xiangQing',query:{id:message.id,title:message.title}}">{{message.title}}</router-link>&nbsp;&nbsp;
			</li>
        

命名路由小结

- 作用:可以简化路由的跳转,不用书写长长的path

- 给路由命名

	{
        path:'/demo',
        component:Demo,
        children:[
            {
                path:'test',
                component:Test,
                children:[
                    {
                          name:'hello' //给路由命名
                        path:'welcome',
                        component:Hello,
                    }
                ]
            }
        ]
    }
    
- 简化跳转

    <!--简化前,需要写完整的路径 -->
    <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>

前端ajax请求携带的参数有两种情况

- 查询字符串query: www.baidu.com/?wd=dongdong&code=100

- 路径参数params: www.baidu.com/dongdong/100 # dongdong和100并不是url路径,而是params参数


params参数介绍(和query参数类似,只不过url路径不同)

### index.js
......
{
    path:'message',
    component:Message,
    children:[
        {	
            name:'xiangQing',
            // path:'detail',
            path:'detail/:id/:title', // path写成这种形式"/:xxx"
            ......
        }
    ]
},

### Message.vue
......
<li v-for="message in messageList" :key="message.id">
				<!-- <router-link :to="{name:'xiangQing',query:{id:message.id,title:message.title}}">{{message.title}}</router-link>&nbsp;&nbsp; -->
													<!--用法和query类似,只不过换了一个称呼而已-->
				<router-link :to="{name:'xiangQing',params:{id:message.id,title:message.title}}">{{message.title}}</router-link>&nbsp;&nbsp;
			</li>
			
### Detail.vue
<template>
	<ul>			<!--接收参数并渲染-->
		<li>消息编号: {{$route.params.id}}</li>
		<li>消息内容: {{$route.params.title}}</li>
	</ul>
</template>

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

<style>
</style>

  • params的坑,不支持和path一起配置,只能和name配置搭配
- name写法,没有问题
	<router-link :to="{name:'xiangQing',params:{id:message.id,title:message.title}}">{{message.title}}</router-link>&nbsp;&nbsp;
- path写法,找不到路径
	<router-link :to="{path:'/home/message/detail',params:{id:message.id,title:message.title}}">{{message.title}}</router-link>&nbsp;&nbsp;

路由的params参数小结

- 配置路由,声明接收params参数

   {
   	path:'/home',
   	......
   	children:[
   		{
   			path:'news',
   			......
   		},
   		{
   			component:Message,
   			children:[
   				{
   					name:'xiangqing',
   					path:'detail/:id/:title', //使用占位符声明接收params参数
   					component:Detail
   				}
   			]
   		}
   	]
   }

- 传递参数

   <!-- 跳转并携带params参数,to的字符串写法 -->
   <router-link :to="/home/message/detail/666/你好">跳转</router-link>
   				
   <!-- 跳转并携带params参数,to的对象写法 -->
   <router-link 
   	:to="{
   		name:'xiangqing',
   		params:{
   		   id:666,
               title:'你好'
   		}
   	}"
   >跳转</router-link>


- 接收参数
   $route.params.id
   $route.params.title

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

props参数介绍

  • 作用:收/传参数
- 第一种写法:写死的数据,很少用

### index.js
......
{
    path:'message', 
   ......
    children:[
        {	
            name:'xiangQing',
            path:'detail/:id/:title',
            component:Detail,
            props:{name:'JimGreen',age:20} // 传递写死的数据
        }
    ]
},

### Detail.vue
<template>
	<ul>
		<li>消息编号: {{$route.params.id}}</li>
		<li>消息内容: {{$route.params.title}}</li>
		<li>{{name}}</li> <!--运用-->
		<li>{{age}}</li>
	</ul>
</template>

<script>
	export default {
		name:'Detail',
		props:['name','age'] // 接收router props配置项
	}
</script>

<style>
</style>

- 第二种写法: props值为'true',表示接收所有的params参数,再传给 Detail组件
  优势: 不用再写一堆'计算属性'去简化插值语法,props配置项帮助我们简化代码

### index.js
......
{
    path:'message', 
   ......
    children:[
        {	
            name:'xiangQing',
            path:'detail/:id/:title',
            component:Detail,
            props:true // 接收上面的path的id和title
        }
    ]
}

### Detail.vue
<template>
	<ul>
		
		<!-- <li>消息编号: {{$route.params.id}}</li>
		<li>消息内容: {{$route.params.title}}</li> -->
		
		<li>消息编号: {{id}}</li> <!--使用-->
		<li>消息内容: {{title}}</li>
	</ul>
</template>

<script>
	export default {
		name:'Detail',
		props:['id','title'] // 接收
	}
</script>

<style>
</style>

- 第三种写法,函数式,效果和布尔值形式类似

### index.js
......
{
    path:'message', 
   ......
    children:[
        {	
            name:'xiangQing',
            path:'detail/:id/:title',
            component:Detail,
            props($route){ // 函数式写法,必须return,自动接收$route
            return {
                    id:$route.params.id,
                    title:$route.params.title
                }
            }
        }
    ]
}

- 注意事项: query也支持这种写法
	props($route){
        return {
            id:$route.query.id,
            title:$route.query.title
        }
    }
    
- 还支持"解构写法":

	children:[
        {	
            name:'xiangQing',
            path:'detail',
            component:Detail,
            props({query}){ // 解构 query对象
                return {
                    id:query.id,
                    title:query.title
                }
            }
        }
    ]
    
    
- 可以支持更进一步的'解构写法'

	children:[
        {	
            name:'xiangQing',
            path:'detail',
            component:Detail,
            props({query:{id,title}}){ // 进一步的解构
            return {id,title}
            }
        }
    ]

	

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
		}
	}
}

浏览器历史记录的两种模式

  • push模式:追加模式,叠积木一层一层的叠下去(浏览器的默认历史记录效果)
  • replace模式:用一条历史记录,替换另外一条历史记录(以新换旧)
### App.vue
......
<div class="list-group">
	<!--增加replace属性即可(简写: :replace="true")-->
    <router-link replace class="list-group-item" active-class="active" :to="{name:'guanYu'}">About</router-link>
    <router-link replace class="list-group-item" active-class="active" to="/home">Home</router-link>
</div>

replace小结

1. 作用:控制路由跳转时操作浏览器历史记录的模式

2. 浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push

3. 如何开启replace模式:<router-link replace .......>News</router-link>
  • 主要使用的属性: "$router"
<template>
	<div>
		<ul>
			<li v-for="message in messageList" :key="message.id">
				
				// 之前的路由实现方式
				<router-link :to="{name:'xiangQing',query:{id:message.id,title:message.title}}">{{message.title}}</router-link>&nbsp;&nbsp;
				// 现在的实现方式
				<button type="button" @click="pushShow(message)">push</button>
			</li>
		</ul>
		<hr >
		<router-view></router-view>
		
	</div>
</template>

<script>
	export default {
		name:'Message',
		data(){
			return {
				messageList:[
					{id:'001',title:'1号消息'},
					{id:'002',title:'2号消息'},
					{id:'003',title:'3号消息'},
				]
			}
		},
		methods:{
			pushShow(m){
				this.$router.push({ // $router.push实现路由跳转(push模式)
					name:'xiangQing', // 跳到哪里去
					query:{id:m.id,title:m.title} // 携带的参数
				})
			}
		}
	}
</script>
  • 使用$router实现浏览器的前进后退跳转功能
### App.vue
<template>
  <div>
    <div class="row">
      <div class="col-xs-offset-2 col-xs-8">
        <div class="page-header"><h2>Vue Router Demo</h2></div>
        <!--新增功能按钮-->
		<button type="button" @click="back">后退</button>
		<button type="button" @click="forward">前进</button>
		<button type="button" @click="go">跳跳</button>
      </div>
    ......
</template>

<script>
	export default {
		name:'App',
		methods:{
			back(){
				this.$router.back() // 浏览器历史记录后退
			},
			forward(){
				this.$router.forward() // 浏览器历史记录前进
			},
			go(){
				this.$router.go(2); // 前进2个历史记录(负数就是后退)
			}
		}
	}
</script>

$router小结

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

 //$router的两个API

      this.$router.push({ // push模式

       name:'xiangqing',

    ​     params:{

    ​      id:xxx,

    ​      title:xxx

    ​     }

      })

      

      this.$router.replace({ // replace模式

       name:'xiangqing',

    ​     params:{

    ​      id:xxx,

    ​      title:xxx

    ​     }

      })

      this.$router.forward() //前进

      this.$router.back() //后退

      this.$router.go() //可前进也可后退

路由缓存技术

  • 引入场景demo: NewsMessage组件互相切换的时候,实质就是组件被销毁,然后又重新创建的过程
### News.vue
<template>
	......
</template>

<script>
	export default {
		name:'News',
		beforeDestroy(){
			console.log('News组件即将被销毁了') // 两个组件之前切换
		}
	}
</script>
  • 如何阻止这种默认的行为呢?使用keep-alive即可(组件之间再切换,不会被销毁了)
### Home.vue
<template>
	<div>
		......
			<keep-alive> <!--包裹起来即可(这种写法默认所有的子组件都缓存)-->- 
				<router-view></router-view>
			</keep-alive>
	</div>
</template>

  • 如果只想单单缓存News组件,可以这么写,加上include属性
### Home.vue
......
<keep-alive include="News"> <!--只缓存News组件-->
	<router-view></router-view>
</keep-alive>
  • 如果缓存多个,可以这么写
### Home.vue
......
<keep-alive :include="['News','Message']"> <!--缓存多个组件-->
	<router-view></router-view>
</keep-alive>

缓存路由组件小结

- 作用:让不展示的路由组件保持挂载,不被销毁(应用场景: 保留用户的输入内容)

<keep-alive include="News"> 

​    <router-view></router-view>

</keep-alive>

两个新的生命周期钩子activateddeactivated

### News.vue
<template>
	<ul>
		<li :style="{opacity}">欢迎学习vue</li> <!--新增效果-->
		<li>news001</li>
		<li>news002</li>
		<li>news003</li>
	</ul>
</template>

<script>
	export default {
		name:'News',
		data(){
			return {
				opacity:1
			}
		},
		// beforeDestroy(){
		// 	console.log('News组件即将被销毁')
		// 	clearInterval(this.timer)
		// },
		// mounted(){
		// 	this.timer = setInterval(()=>{
		// 		this.opacity -= 0.01
		// 		if(this.opacity <= 0) this.opacity = 1
		// 	},16)
		// },
		activated(){ // 当组件被激活的时候,执行逻辑
			this.timer = setInterval(()=>{
				this.opacity -= 0.01
				if(this.opacity <= 0) this.opacity = 1
			},16)
		},
		deactivated(){ // 当组件失活的时候,执行逻辑
			console.log('News组件即将被销毁')
			clearInterval(this.timer)
		}
	}
</script>

两个新的生命周期钩子小结

- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态

- activated路由组件被激活时触发。

- deactivated路由组件失活时触发。

全局路由前置守卫初体验

### index.js(使用router接收实例,目的是加点逻辑,再导出)
......

const router = new VueRouter({
	routes:[
		{	
			name:'guanYu',
			......
		},
		{
			name:'jia',
			......
			children:[
				{
					name:'xinwen',
					......
				},
				{
					name:'xinxi',
					......
					children:[
						{	
							name:'xiangQing',
							......
						}
					]
				},
			]
		},
	]
})

router.beforeEach((to,from,next)=>{
	console.log(to) // 目标路由对象
	console.log(from) // 源路由对象
	next() // 放行(不加这句,路由无法到达目标组件,导致组件内容无法渲染)
})


export default router
- router.beforeEach(回调函数)
	- 初始化的时候会被调用一次
	- 每次路由切换之前,会被调用
  • demo演示,只有localStorage存在键值对name:Jim Green才允许访问News组件message组件
### index.js
import VueRouter from 'vue-router'
......


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

router.beforeEach((to,from,next)=>{
	
	if(to.path === '/home/news' || to.path === '/home/message'){
		if(localStorage.getItem('name') === 'Jim Green'){ // 校验键值对
			next()
		}else{
			alert('名字不对,不能访问')
		}
	}else{ // 其他路径均放行
		next()
	}
	
})


export default router
  • 优化上述demo逻辑: 若有很多个路径需要校验权限的情况下,使用||连接各种情况,代码显得很冗长(可读性差),解决办法
- 利用 route.meta属性,我们可以往里头添加自定义的key-value,帮助我们优化逻辑

- 这里我们往需要校验的path添加 isAuth:true

### index.js
{
    name:'jia',
    path:'/home',
    component:Home,
    children:[
        {
            name:'xinwen',
            path:'news',
            component:News,
            meta:{isAuth:true} // 利用meta新增自定义key-value
        },
        {
            name:'xinxi',
            path:'message', 
            component:Message,
            meta:{isAuth:true}, // 利用meta新增自定义key-value
            children:[......]
}
......
router.beforeEach((to,from,next)=>{
	
	// if(to.path === '/home/news' || to.path === '/home/message'){
	if(to.meta.isAuth){ // 相比上面的代码,可读性强很多
		if(localStorage.getItem('name') === 'Jim Green'){
			next()
		}else{
			alert('名字不对,不能访问')
		}
	}else{
		next()
	}
	
})

全局路由后置守卫(比较少用到)

- 初始化的时候会被调用一次
- 每次路由切换之后,会被调用
### index.js
......
router.afterEach((to,from)=>{
	document.title = to.meta.title || 'Demo测试' // 变更浏览器左上角标题
})

路由守卫小结

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

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

- 全局守卫
 //全局前置守卫:初始化时执行、每次路由切换前执行

      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'

       }

      })

独享守卫: 当要进入路由组件的时候,触发beforeEnter事件

  • 作用类似于全局前置守卫beforeEach
  • 区别在于,一个是全局,操作router,另外一个是操作单路由配置项
  • 以下demo演示,效果与beforeEach一模一样
### index.js
import VueRouter from 'vue-router'
......


const router = new VueRouter({
	routes:[
		{	
			name:'guanYu',
			......
		},
		{
			name:'jia',
			......
			children:[
				{
					name:'xinwen',
					path:'news',
					component:News,
					meta:{isAuth:true,title:'新闻'},
					beforeEnter:(to,from,next)=>{ // 独享守卫beforeEnter,这里不能写成 beforeEnter(){...} 这种形式(钩子配置)
						if(to.meta.isAuth){
							if(localStorage.getItem('name') === 'Jim Green'){
								next()
							}else{
								alert('名字不对,不能访问')
							}
						}else{
							next()
						}
					}
				},
				{
					name:'xinxi',
					......
					beforeEnter:(to,from,next)=>{ // 一样的套路
						if(to.meta.isAuth){
							if(localStorage.getItem('name') === 'Jim Green'){
								next()
							}else{
								alert('名字不对,不能访问')
							}
						}else{
							next()
						}
					},
					children:[
						......
					],
					
				},
			]
		},
	]
})

// router.beforeEach((to,from,next)=>{
	
// 	if(to.meta.isAuth){
// 		if(localStorage.getItem('name') === 'Jim Green'){
// 			next()
// 		}else{
// 			alert('名字不对,不能访问')
// 		}
// 	}else{
// 		next()
// 	}
	
// })

// router.afterEach((to,from)=>{
// 	document.title = to.meta.title || 'Demo测试'
// })


export default router

组件内守卫

  • beforeRouteEnter:通过路由规则,进入该组件时被调用(类似router.beforeEach)

  • beforeRouteLeave:通过路由规则,离开该组件时被调用

    - 不用于"router.afterEach","afterEach"是停留在组件触发,"beforeRouteLeave"是离开组件以后触发
    
### About.vue

<template>
	<div>
		<h1>我是About组件的内容</h1>
	</div>
</template>

<script>
	export default {
		name:'About',
		beforeRouteEnter(to,from,next){ 
			if(to.meta.isAuth){
				if(localStorage.getItem('name') === 'Jim Green'){
					next()
				}else{
					alert('名字不对,不能访问')
				}
			}else{
				next()
			}
		},
		beforeRouteLeave(to,form,next){
			console.log('@@@-beforeRouteLeave')
			next()
		}
	}
</script>

<style>
</style>

路由的两种工作模式

- 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值(router插件的默认效果)

    - hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器

    	-  hash模式

          - 地址中永远带着#号,不美观 

          - 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法

          - 兼容性较好

    - history模式

          - 地址干净,美观 

          - 兼容性和hash模式相比略差

          - 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题
            比如: http://localhost:8080/home/news,这里的news其实不是路径

const router = new VueRouter({
	mode:'history', // 修改为history模式
	routes:[......]
  • 好文推荐https://blog.csdn.net/lovefengruoqing/article/details/117024141

打包编译vue文件,给后端

- 命令: npm run build // 会生成 dist目录(包含 html,css.js文件)