VueRouter

Posted CloudSky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VueRouter相关的知识,希望对你有一定的参考价值。

相关理解

vue-router

理解

vue的一个插件库,专门用来实现SPA应用。

对SPA应用的理解

  1. 单个Web应用(single page web application, SPA)。
  2. 整个应用只有一个完整的页面
  3. 点击页面中的导航链接不会刷新页面,只会做页面的局部更新
  4. 数据需要通过ajax请求获取。

路由的理解

什么是路由?

  1. 一个路由就是一组映射关系 (key——value)
  2. key为路径, value可能是function或者component

路由分类

后端路由

理解

valuefunction,用于处理客户端提交的请求。

工作过程

服务器接收到一个请求时,根据请求路径找到匹配的函数类来处理请求,返回响应数据

前端路由

理解

valuecomponent,用于展示页面内容。

工作过程

当浏览器的路径发生改变时,对应的组件就会显示。

基本路由

基本使用

1. 安装

安装vue-router: npm i vue-router@3
ps: vue-router3只能在vue2中使用,vue-router4在vue3中使用。

2. 应用插件

main.js里应用插件:

//引入路由
import VueRouter from \'vue-router\'
//使用路由
Vue.use(VueRouter)

3. 编写router配置项

创建src/router/index.js

//该文件用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from \'../components/Home\'
import About from \'../components/About\'


//创建并暴露一个路由器
export default new VueRouter(
    routes: [
         
            path: \'/Home\',
            component: Home
         ,
         
            path: \'/About\',
            component: About
         
    ]
)

4. 使用路由器

在main.js里使用路由器

//引入路由器
import router from \'./router\'
...
// 创建Vue实例对象 
new Vue(
  render: h => h(App),
  router//使用路由器
).$mount(\'#app\')

5. 实现切换

active-class可以配置高亮样式:

<router-link active-class="active" to="/about">About</router-link>
<router-link active-class="active" to="/home">Home</router-link>

6. 指定展示位置

<router-view></router-view>

注意

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

多级路由

配置

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

routes: [
      
         path: \'/Home\',
         component: Home,
         children: [//通过children配置子级路由
            
               path: \'news\', //路由匹配子级时会自动加/,所以这里不能写/news
               component: News
            ,
            
               path: \'message\',
               component: Message
            
         ]
      
   ]

跳转

<!-- to一定要带上父级路径 -->
<router-link to="/home/news" >News</router-link>

路由的query参数

使用

  1. 传递参数
 <!-- 跳转路由并携带query参数,to的字符串写法 -->
<!-- 加:会将""的内容当js模板字符串``去解析,传js变量用$ -->
<router-link :to="`/home/message/detail?id=$item.id&title=$item.title`"> item.title </router-link>

<!-- 对象写法(推荐) -->
<router-link
	:to="
		path: \'/home/message/detail\',
		query: 
			id: item.id,
			title: item.title
		
	">
	 item.title 
</router-link>
  1. 接收参数
$route.query.id
$route.query.title

命名路由

作用

在某些情况可以简化路由跳转的代码。

使用

  1. 给路由命名

	path: \'home\',
	component: Home,
	children: [
		path: \'message\',
		component: Message,
		children: [
			
			name: \'Detail\',//给路由命名
			path: \'Detail\',
			component: Detail
			
		]
	]

  1. 简化跳转
<!-- 简化前需要写完整路径 -->
<router-link to="/home/message/detail">跳转</router-link>
<!-- 简化后,直接通过名字跳转 -->
<router-link :to="name: \'detail\'">跳转</router-link>

<!-- 简化写法配合传递参数 -->
<router-link 
	:to="
		name: \'detail\',
		query: 
			id: 666,
			title: \'hello\'
		
	"
></router-link>

路由的params参数

使用

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

         path: \'/Home\',
         component: Home,
         children: [
            
               path: \'news\',
               component: News
            ,
            
               path: \'message\',
               component: Message,
               children: [
                  
                     name: \'Detail\',
                     path: \'Detail/:id/:title\', //:xxx占位符,用于parmas传参
                     component: Detail
                  
               ]
            
         ]
      
  1. 传递参数
<!-- 跳转路由并携带params参数,to的字符串写法 -->
<router-link :to="`/home/message/detail/$item.id/$item.title`"> item.title </router-link>

<!-- 跳转路由并携带params参数,to的字符串写法 -->
<!-- !!!!!!! params必须使用name跳转路由,不能使用path !!!!!! -->
<router-link 
	:to="
		name: \'Detail\',
		params: 
			id: item.id,
			title: item.title
		
	"
>
 item.title 
</router-link>

路由的props配置

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

  1. 第一种写法
//
//值为对象,该对象中所有key-value都会以props的形式传给Detail组件
props: 
	a: 1,b: \'hello\'


  1. 第二种写法
//值为布尔值,若布尔值为真,就会把该路由组件收到的pramas参数以props的形式传给Detail组件
props: true
  1. 第三种写法
//值为函数,该函数返回的对象种每一组key-value都会通过props传给Detail组件
props($route) 
	return 
		id: $route.query.id,
		title: $route.query.title
	

router-link的replace属性

作用

控制路由跳转时操作浏览器历史记录的模式。
浏览器的历史有两种写入方式:

  1. push:追加记录。
  2. replace:替换当前记录(不是所有记录,而是当前记录)。
    路由跳转默认为push

使用

<!-- 完整写法是replace="true",但是replace的默认值就是true,所以可以直接只写一个replace -->w
<router-link replace ...></router-link>

编程式路由导航

作用

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

使用

//push方法跳转
this.$router.push(
	name: \'Detail\',
	query: 
		id: item.id,
		title: item.title
	
)

//replace方法跳转
this.$router.replace(
	name: \'Detail\',
	query: 
		id: item.id,
		title: item.title
	
)

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

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

//前进n步
this.$router.go(n)

缓存路由组件

作用

让不展示的路由组件保持挂载,不被销毁。

使用

  1. 缓存一个路由组件
<!-- 不写include则所有该组件的路由都会被缓存 -->
<!-- 要写组件名!而不是路由名 -->
<keep-alive include="News">
	<router-view></router-view>
</keep-alive>
  1. 缓存多个路由组件
<keep-alive :include="[\'News\', \'Message\']">
	<router-view></router-view>
</keep-alive>

两个新的生命周期钩子

作用

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

使用

activated()...,//路由组件被激活时调用
deactivated()...//路由组件失活时调用

路由守卫

作用

对所有路由进行权限控制。

分类

  1. 全局守卫
  2. 独享守卫
  3. 组件内守卫

全局路由守卫

全局前置守卫

初始化时和每次路由切换之前执行。

// to目的地, from始发地, next到达执行
//必须执行next()才能实现路由跳转
router.beforeEach((to, from, next) => 
   console.log(\'前置\',to, from);
   if(to.meta.isAuth) //判断是否需要鉴定权限
      if(localStorage.getItem(\'school\') === \'cloud\') 
         next()//放行
      else 
         alert(\'学校名称不对,无权查看\')
      
   else 
      next()//放行
   
)

全局后置守卫

路由切换之后执行。

router.afterEach((to, from) => 
    console.log(\'后置\',to, from);
   //默认title是cloud,路由跳转后根据路由相应的title更改
   document.title = to.meta.title || \'cloud\'//修改网页的title
)

独享路由守卫

作用

对某个路由进行权限控制。
只有独享前置守卫,没有独享后置守卫,可以与全局后置守卫配合使用。

beforeEnter(to, from, next) 
	console.log(\'独享\', to, from);
	if (to.meta.isAuth) //判断是否需要鉴定权限
		if (localStorage.getItem(\'school\') === \'cloud\') 
			next()
		
		else alert(\'学校名称不对,无权查看\')
	
	else next()


组件内路由守卫

  1. 通过路由规则,进入该组件时调用。
beforeRouteEnter(to, from, next) ...
  1. 通过路由规则,离开该组件时调用。
beforeRouteLeave(to, from, next) ...

路由器的两种工作模式

对于一个url来说,什么是hash值?

  • #后面的内容就是hash值。

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

hash模式

  1. 地址中永远带着#号,不美观。
  2. 若以后将地址通过第三方手机APP分享,若APP校验严格,则地址会被标记为不合法。
  3. 兼容性较好。(But IE已死)

history模式

  1. 地址干净、美观。
  2. 兼容性比起hash略差。
  3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。

修改模式

修改模式在路由配置中添加mode属性,默认值是hash

mode: \'history\'

VueRouter爬坑第四篇-命名路由编程式导航


VueRouter系列的文章示例编写时,项目是使用vue-cli脚手架搭建。

项目搭建的步骤和项目目录专门写了一篇文章:点击这里进行传送

后续VueRouter系列的文章的示例编写均基于该项目环境。


 VueRouter系列文章链接

  《VueRouter爬坑第一篇-简单实践

  《VueRouter爬坑第二篇-动态路由

  《VueRouter爬坑第三篇-嵌套路由

  《VueRouter爬坑第四篇-命名路由、编程式导航》


 阅读目录

一.前言

二.命名路由

三.编程式导航

四.命名路由+$router.push


一.前言

  前面三篇VueRouter系列文章,第一篇我们先是对路由做了一个简单的实践。

  第二篇实践了动态路由的使用;

  第三篇实践了嵌套路由的使用场景和用法;

  本篇文章将实践一下命令路由和编程式导航这两个名词所涵盖的技术点。

二.命名路由

  命名路由,字面意思就是给路由起个名字。

  那给路由起了名字有什么作用呢?

  前面几篇文章中,我们配置<router-link>的to属性值时,设置的是routes中的path。

  那么当我们给路由配置名称后,这个to属性的值就可以设置为路由的名称。

  我们接着上一节演示的那个场景示例,将其使用嵌套路由进行重写。

1.给路由配置名称

  首先呢,我们先在router.js中给路由添加名称

E:MyStudy estVueDemosrc outer outer.js

 1 import Vue from "vue"
 2 import Router from "vue-router"
 3 Vue.use(Router)
 4 
 5 // 引入路由需要映射的组件
 6 import Content from ‘@/components/Content.vue‘
 7 import ProductDetail from ‘@/components/ProductDetail.vue‘
 8 const routes = [
 9     {
10         path: ‘/products‘,  
11         name: ‘productsRoute‘,   // 给路由配置名称
12         component: Content, 
13         children:[
14             {
15                 path: ‘/productDetail/:id‘, 
16                 name: ‘productDetailRoute‘,  // 给路由配置名称
17                 component: ProductDetail    
18             }
19         ]
20     }
21 ]
22 
23 const router = new Router({
24     routes: routes
25 })
26 
27 export default router

  新增的代码为:11行和16行。

  可以看到,为路由配置名称的语法就是在单条路由配置中添加name属性即可。

2.重写组件中的路由跳转代码

  给路由配置名称后,接着需要做的事情就是修改组件中路由跳转的代码。

  先修改App.vue组件中的路由跳转代码

E:MyStudy estVueDemosrcApp.vue

 1 <template>
 2   <div id="app">
 3     <!-- 菜单  -->
 4     <ul>
 5       <li v-for=‘(item,index) in menuList‘ v-bind:key=‘index‘ >
 6           <router-link v-bind:to=‘{name: item.routeName}‘>{{item.name}}</router-link>
 7       </li>
 8     </ul>
 9     <!-- 内容区 -->
10     <router-view />
11   </div>
12 </template>
13 
14 <script>
15 export default {
16   name: App,
17   data() {
18     return {
19       menuList: [
20         {
21           url: /index,
22           name: 首页,
23           routeName: indexRoute,
24         },{
25           url: /products,
26           name: 产品,
27           routeName: productsRoute,
28         }
29       ]
30     }
31   }
32 }
33 </script>
34 
35 <style>
36 #app {
37   font-family: ‘Avenir‘, Helvetica, Arial, sans-serif;
38   -webkit-font-smoothing: antialiased;
39   -moz-osx-font-smoothing: grayscale;
40   color: #2c3e50;
41 }
42 ul {
43     display: inline-block;
44     width: 100px;
45     border: 1px solid #ddd;
46     padding: 100px 0px 100px 20px;
47     position: fixed;
48     top: -10px;
49     bottom: 0px;
50 }
51 a{
52   text-decoration: none;
53 }
54 </style>

 

  App组件中,修改的代码在第6行,同时新增了22行、26行两行代码。

  核心的代码如下:

<router-link v-bind:to=‘{name: item.routeName}‘>{{item.name}}</router-link>

 

  接着是Content.vue组件

E:MyStudy estVueDemosrcComponentsContent.vue

 1 <template>
 2     <div class=‘productContent‘> 
 3         <div class="productList">
 4             <!-- 产品列表  -->
 5             <h1>产品列表</h1>
 6             <p v-for="(item,index) in productsList" v-bind:key=‘index‘> 
 7                 <router-link v-bind:to="{name: item.routeName,params:{id:index+1}}">{{item.name}}</router-link>
 8             </p> 
 9         </div>
10         <!-- 产品详情 -->
11         <router-view />
12     </div>
13 </template>
14 <script>
15 export default {
16     name: Content,
17     data() {
18         return {
19             productsList: [
20                 {
21                     url: /productDetail/1,
22                     name: 产品1,
23                     routeName: productDetailRoute
24                 },{
25                     url: /productDetail/2,
26                     name: 产品2,
27                     routeName: productDetailRoute
28                 }
29             ]
30         }
31     }
32 
33 }
34 </script>
35 <style scoped>
36     .productContent{
37         margin-left: 150px;
38     }
39     .productList{
40         border:1px solid #ddd;
41         margin: 10px;
42     }
43 </style>

  Content.vue组件中,修改了第7行的代码,同时新增22行、26行两行代码。

  核心的代码如下:

<router-link v-bind:to="{name: item.routeName,params:{id:index+1}}">{{item.name}}</router-link>

  ProductDetail.vue组件没有修改。

 

  这里呢,总结一下:

  1.route.js中配置路由名称使用name选项

  2.route-link使用name时,需要使用字典{name: ‘路由名称‘},而不能直接向使用path一样绑定一个字符串

  3.route-link编写动态路由的动态参数使用params设置

  

  代码修改完成,查看结果:

  技术图片

  可以看到,结果和之前的一样。

三.编程式导航

  在前面几篇VueRouter的学习过程中,我们一直使用的是<router-link>编写可跳转的URL。

  官方文档把这种方式成为声明式的导航

  而另外一种可以与之替代的就是编程式导航:使用router实例的push方法实现URL跳转

还是嵌套路由这个示例router.js不做修改,依然是前面的代码

1.将App组件中的route-link改为router.push实现

E:MyStudy estVueDemosrcApp.vue

 1 <template>
 2   <div id="app">
 3     <!-- 菜单  -->
 4     <ul>
 5       <li v-for=‘(item,index) in menuList‘ v-bind:key=‘index‘ >
 6           <p v-on:click=‘menuHandler(item.url)‘> {{ item.name }}</p>
 7       </li>
 8     </ul>
 9     <!-- 内容区 -->
10     <router-view />
11   </div>
12 </template>
13 
14 <script>
15 export default {
16   name: App,
17   data() {
18     return {
19       menuList: [
20         {
21           url: index,
22           name: 首页,
23           routeName: indexRoute,
24         },{
25           url: products,
26           name: 产品,
27           routeName: productsRoute,
28         }
29       ]
30     }
31   },
32   methods: {
33     menuHandler: function(url){
34       this.$router.push(url);   //或者$router.push(url);
35     }
36   }
37 }
38 </script>
39 
40 <style>
41 #app {
42   font-family: ‘Avenir‘, Helvetica, Arial, sans-serif;
43   -webkit-font-smoothing: antialiased;
44   -moz-osx-font-smoothing: grayscale;
45   color: #2c3e50;
46 }
47 ul {
48     display: inline-block;
49     width: 100px;
50     border: 1px solid #ddd;
51     padding: 100px 0px 100px 20px;
52     position: fixed;
53     top: -10px;
54     bottom: 0px;
55 }
56 li{
57   cursor: pointer;
58 }
59 a{
60   text-decoration: none;
61 }
62 </style>

App.vue组件中修改了第6行的代码;同时新增了一个methods:menuHandler处理菜单点击的逻辑。

  menuHandler函数中的逻辑就是vue编程式导航的实现代码

  App组件中的修改总结一下:

    menuHandler方法中的this.$router.push(url)代码,它和$router.push(url)是等价的。

    而且当我们给push传入一个字符串参数时,默认是传递的值是url,匹配的就是routes中的path参数

    因此menuHandler方法中的逻辑也可以写成this.$router.push({path:url})或者$router.push({path:url}) 

 

2.Content组件中的route-link改为router.push实现

E:MyStudy estVueDemosrcComponentsContent.vue

 1 <template>
 2     <div class=‘productContent‘> 
 3         <div class="productList">
 4             <!-- 产品列表  -->
 5             <h1>产品列表</h1>
 6             <p v-for="(item,index) in productsList" v-bind:key=‘index‘ v-on:click=‘productHandle(index)‘> 
 7                 {{item.name}}
 8             </p> 
 9         </div>
10         <!-- 产品详情 -->
11         <router-view />
12     </div>
13 </template>
14 <script>
15 export default {
16     name: Content,
17     data() {
18         return {
19             productsList: [
20                 {
21                     url: /productDetail/1,
22                     name: 产品1,
23                     routeName: productDetailRoute
24                 },{
25                     url: /productDetail/2,
26                     name: 产品2,
27                     routeName: productDetailRoute
28                 }
29             ]
30         }
31     },
32     methods: {
33         productHandle: function(index) {
34             var id = index+1;
35             this.$router.push(/productDetail/+id); //或者$router.push(‘/productDetail/‘+id);
36         }
37     }
38 
39 }
40 </script>
41 <style scoped>
42     .productContent{
43         margin-left: 150px;
44     }
45     .productList{
46         border:1px solid #ddd;
47         margin: 10px;
48     }
49     p{
50         cursor: pointer;
51     }
52 </style>

     Content.vue组件编程式导航写法为:this.$router.push(‘/productDetail/‘+id);

  其中默认传递的字符串参数匹配的是路由配置中的path

  因此this.$router.push(‘/productDetail/‘+id)也可以是如下写法:

    this.$router.push({path: ‘/productDetail/‘+id);

  注意:

  当使用path去匹配路由的时候,params这个参数是不生效的。

  因此this.$router.push({path: ‘productDetail‘,params:{id:id})这种写法是无效的。

  

  代码修改完成,我们还是来看下结果对不对

  技术图片

  可以看到,和前面命令式写法、路由命名这两个是相同的结果。

四.命令路由+$router.push

  vuerouter系列的前三篇文章中,我们使用路由配置的path选项结合声明式导航<router-link>实现路由跳转。

  本篇中先是使用路由配置中的name结合声明式导航<router-link>实现路由跳转。

  接着实践了编程式导航$router.push并匹配路由配置中的path实现路由跳转。

  那么在排列组合一下,我们就在实践一下编程式导航$router.push结合命令路由实现路由跳转。

E:MyStudy estVueDemosrcApp.vue

<template>
  <div id="app">
    <!-- 菜单  -->
    <ul>
      <li v-for=‘(item,index) in menuList‘ v-bind:key=‘index‘ >
          <p v-on:click=‘menuHandler(item.url)‘> {{ item.name }}</p>
      </li>
    </ul>
    <!-- 内容区 -->
    <router-view />
  </div>
</template>

<script>
export default {
  name: App,
  data() {
    return {
      menuList: [
        {
          url: index,
          name: 首页,
          routeName: indexRoute,
        },{
          url: products,
          name: 产品,
          routeName: productsRoute,
        }
      ]
    }
  },
  methods: {
    menuHandler: function(url){
      //使用命名路由
      this.$router.push({name:productsRoute})
    }
  }
}
</script>

<style>
#app {
  font-family: ‘Avenir‘, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
}
ul {
    display: inline-block;
    width: 100px;
    border: 1px solid #ddd;
    padding: 100px 0px 100px 20px;
    position: fixed;
    top: -10px;
    bottom: 0px;
}
li{
  cursor: pointer;
}
a{
  text-decoration: none;
}
</style>

 

  核心代码如下:

menuHandler: function(url){
     //使用命名路由
    this.$router.push({name:‘productsRoute‘})
}

 

E:MyStudy estVueDemosrcComponentsContent.vue

 1 <template>
 2     <div class=‘productContent‘> 
 3         <div class="productList">
 4             <!-- 产品列表  -->
 5             <h1>产品列表</h1>
 6             <p v-for="(item,index) in productsList" v-bind:key=‘index‘ v-on:click=‘productHandle(index)‘> 
 7                 {{item.name}}
 8             </p> 
 9         </div>
10         <!-- 产品详情 -->
11         <router-view />
12     </div>
13 </template>
14 <script>
15 export default {
16     name: Content,
17     data() {
18         return {
19             productsList: [
20                 {
21                     url: /productDetail/1,
22                     name: 产品1,
23                     routeName: productDetailRoute
24                 },{
25                     url: /productDetail/2,
26                     name: 产品2,
27                     routeName: productDetailRoute
28                 }
29             ]
30         }
31     },
32     methods: {
33         productHandle: function(index) {
34             var id = index+1;
35             //使用命令路由
36             this.$router.push({name:productDetailRoute, params: {id: id}})
37         }
38     }
39 
40 }
41 </script>
42 <style scoped>
43     .productContent{
44         margin-left: 150px;
45     }
46     .productList{
47         border:1px solid #ddd;
48         margin: 10px;
49     }
50     p{
51         cursor: pointer;
52     }
53 </style>

 

  核心代码如下:

productHandle: function(index) {
     var id = index+1;
      //使用命令路由
      this.$router.push({name:‘productDetailRoute‘, params: {id: id}})
}

  关于这两个组件的核心代码我已分别贴出,比较简单这里就不多说了。

  最后的结果也和前面一致。

  

  到此本篇文章完!

 


技术图片

以上是关于VueRouter的主要内容,如果未能解决你的问题,请参考以下文章

VueRouter爬坑第一篇-简单实践

前端VueRouter解析

手写VueRouter

手写VueRouter

手写VueRouter

手写VueRouter