Vue路由(router)进一步详解

Posted 小田『开心馆』

tags:

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

Vue路由(router)进一步详解


本篇文章主要针对已经掌握Vue路由(router)基础以及路由嵌套的用户群体,如果你是Vue路由初学者的话,不仿先去看看 【Vue路由(router)的基本使用】这篇文章

接上一篇文章理解Vue路由中常用的知识点

在实际开发过程中,我们可能不单单要实现简单的页面跳转动作,可能在页面跳转的同时,我们需要携带一些数据给对应的路由组件,也就是说,涉及路由的传参,那怎么实现路由传参呢,其实有三种方式可以使得携带参数至指定的路由组件,他们分别是queryparams以及在学组件时已经熟知的props


query属性

切换路由并传递参数用法

传递参数:

<!-- 方法一,字符串写法 -->
<router-link :to="/跳转路径/跳转路径?参数一='xxxx'&参数二='XXXXX'">跳转</router-link>

<!-- 方法二,对象写法 -->
<router-link
  :to="
    path:'/路径/路径/XXX',
    query:
      data1:'XXX',
      data2:'XXX',
      .....
    
  "
>>跳转</router-link>

值得注意的一个点是,在上述用法中,我们所传递的参数都是写死的参数,但开发中更多的情况是我们传递的参数可能是动态的数据,对象写法还是一样的,但是字符串写法又该如何实现呢?

如下:
尚硅谷Vue讲师张天禹介绍了ES6中字符串模板加上直接赋值的写法:

<router-link :to="`/home/messageA/detailA?id=$m.id&title=$m.title`">跳转</router-link>

路由组件中接收参数:

$router.query.XXX
$router.query.XXX
$router.query.XXX

具体实例代码如下:

本篇文章是在【Vue路由(router)的基本使用】的基础上写的,所以重复的,没有改动的代码我就不再展示,这里我们用TestA.vue组件举例,数据存储在TestA.vue中,但我希望把数据传递到它的子路由上,实现动态的数据展示

创建TestA.vue的子路由组件DataList.vue:

<template>
  <div>
      <ul>
          <!-- 采用插值语法就可以拿到父级路由中的数据 -->
          <li>$route.query.introduce</li>
      </ul>
  </div>
</template>

<script>
export default 
    name:'DataList'

</script>

<style>

</style>

src/router/index.js的变化:

//该文件用于创建整个应用的router
//首先,需要引用vue-router
import VueRouter from "vue-router";

//引入路由组件
import TestA from '../pages/TestA'
import TestB from '../pages/TestB'
// 引入二级路由组件
import TestBHzw from '../pages/TestBHzw'
import TestBHyrz from '../pages/TestBHyrz'

import DataList from '../pages/DataList'

//创建并暴露一个VueRouter
export default new VueRouter(
    routes:[
        //配置路由路径和路由组件
        
            //这里的路径可自由定义,但是为了初学者好理解,我就采用和组件同样的命名,防止在写路径的时候搞混
            path:'/TestA',
            component:TestA,     //要跳转到的组件   
            children:[
                
                    path:'DataList',
                    component:DataList
                
            ]
        ,
        
            path:'/TestB',
            component:TestB,
            // 配置二级路由
            children:[
                
                    path:'TestBHzw',     //重点注意,不要加 /
                    component:TestBHzw
                ,
                
                    path:'TestBHyrz',
                    component:TestBHyrz
                
            ]
        
    ]
)

TestA.vue:

<template>
  <div>
    <h4>著名动漫简介</h4>
    <ul>
      <li v-for="i in DataList" :key="i.id">
        <!-- 使用query参数传递动态参数 -->
        <router-link :to="
          path:'/TestA/DataList',
          query:
            introduce:i.introduce
          
        ">i.name</router-link>
      </li>
    </ul>
    <router-view></router-view>
  </div>
</template>

<script>
export default 
    name:'TestA',
    data()
      return
        DataList:[
          
            id:1,
            name:'《海贼王》',
            introduce:'《航海王》是日本漫画家尾田荣一郎作画的少年漫画作品,于1997年7月22日在集英社《周刊少年Jump》开始连载。改编的电视动画《航海王》于1999年10月20日起在富士电视台首播。'
          ,
          
            id:2,
            name:'《火影忍者》',
            introduce:'电视动画《火影忍者》改编自日本漫画家岸本齐史的同名漫画,2002年10月3日在东京电视台系列全6局、岐阜放送首播,共220话;第二季《火影忍者疾风传》于2007年2月15日-2017年3月23日在东京电视台播出,共500话;累计全720话。'
          ,
          
            id:3,
            name:'《斗破苍穹》',
            introduce:'《斗破苍穹》是一部由阅文集团旗下起点中文网作家天蚕土豆同名玄幻长篇经典小说改编的动画。该动画第一季已于2017年1月7日在腾讯视频上映,bilibili同步跟播,共十二集。'
          ,
          
            id:4,
            name:'《鬼灭之刃》',
            introduce:'《鬼灭之刃》是日本漫画家吾峠呼世晴所著的少年漫画,自2016年2月15日—2020年5月11日在集英社《周刊少年Jump》上连载。已完结。'
          
        ]
      
    

</script>

<style scoped>
h4
  text-align: center;

a
  text-decoration: none;

.active:visited
  color: brown;

</style>

其他组件是没有改动过的

效果图:
此时,我们处于一级路由,TestA.vue组件的子路由是没有展示的

当我们鼠标点击对应动漫列表时,就会出现动漫的简介,此时就完成了利用query参数传递数据。


params属性

params属性起到的作用和query差不多,都是用于传递和接收参数,只不过,它是在src/router/index.js中进行配置


        path:'/一级路径',
        component:XXX,
        children:[
            
                path:'二级路径',
                component:XXX,
                children:[
                    name:'name',
                    path:'XXX/:name/:data',   //使用占位符声明,接收params参数,相当于说先占个位置,在路由组件中就可以按照位置进行参数传递
                    component:XXX
                ]
            ,
        ]
    

传递参数:

<!-- 方法一,字符串写法 -->
<router-link :to="XXX/XXX/XXX/参数一/参数二">跳转</router-link>

<!-- 方法二,对象写法 -->
<router-link
   :to="
       name:'XXX',
       params:
           参数一:'XXX',
           参数二:'XXX'
       
   "
>跳转</router-link>

需要强调的一个点是: 路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!

接收参数:

$router.params.XXX
$router.params.XXX

具体实例代码如下:

TestA.vue:

<template>
  <div>
    <h4>著名动漫简介</h4>
    <ul>
      <li v-for="i in DataList" :key="i.id">
        <!-- 使用params参数传递动态参数 注意:params传递参数必须配合name属性-->
        <router-link :to="
          name:'DataName',
          params:
            introduce:i.introduce
          
        ">i.name</router-link>
      </li>
    </ul>
    <router-view></router-view>
  </div>
</template>

<script>
export default 
    name:'TestA',
    data()
      return
        DataList:[
          
            id:1,
            name:'《海贼王》',
            introduce:'《航海王》是日本漫画家尾田荣一郎作画的少年漫画作品,于1997年7月22日在集英社《周刊少年Jump》开始连载。改编的电视动画《航海王》于1999年10月20日起在富士电视台首播。'
          ,
          
            id:2,
            name:'《火影忍者》',
            introduce:'电视动画《火影忍者》改编自日本漫画家岸本齐史的同名漫画,2002年10月3日在东京电视台系列全6局、岐阜放送首播,共220话;第二季《火影忍者疾风传》于2007年2月15日-2017年3月23日在东京电视台播出,共500话;累计全720话。'
          ,
          
            id:3,
            name:'《斗破苍穹》',
            introduce:'《斗破苍穹》是一部由阅文集团旗下起点中文网作家天蚕土豆同名玄幻长篇经典小说改编的动画。该动画第一季已于2017年1月7日在腾讯视频上映,bilibili同步跟播,共十二集。'
          ,
          
            id:4,
            name:'《鬼灭之刃》',
            introduce:'《鬼灭之刃》是日本漫画家吾峠呼世晴所著的少年漫画,自2016年2月15日—2020年5月11日在集英社《周刊少年Jump》上连载。已完结。'
          
        ]
      
    

</script>

<style scoped>
h4
  text-align: center;

a
  text-decoration: none;

.active:visited
  color: brown;

</style>

src/router/index.js:

//该文件用于创建整个应用的router
//首先,需要引用vue-router
import VueRouter from "vue-router";

//引入路由组件
import TestA from '../pages/TestA'
import TestB from '../pages/TestB'
// 引入二级路由组件
import TestBHzw from '../pages/TestBHzw'
import TestBHyrz from '../pages/TestBHyrz'

import DataList from '../pages/DataList'

//创建并暴露一个VueRouter
export default new VueRouter(
    routes:[
        //配置路由路径和路由组件
        
            //这里的路径可自由定义,但是为了初学者好理解,我就采用和组件同样的命名,防止在写路径的时候搞混
            path:'/TestA',
            component:TestA,     //要跳转到的组件   
            children:[
                
                    // 给二级路由起名字
                    name:'DataName',
                    path:'DataList/:introduce',     //起到占位作用
                    component:DataList
                
            ]
        ,
        
            path:'/TestB',
            component:TestB,
            // 配置二级路由
            children:[
                
                    path:'TestBHzw',     //重点注意,不要加 /
                    component:TestBHzw
                ,
                
                    path:'TestBHyrz',
                    component:TestBHyrz
                
            ]
        
    ]
)

DataList.vue:

<template>
  <div>
      <ul>
          <!-- 采用插值语法就可以拿到父级路由中的数据 -->
          <li>$route.params.introduce</li>
      </ul>
  </div>
</template>

<script>
export default 
    name:'DataList'

</script>

<style>

</style>

效果图
鼠标未点击之前:

鼠标点击之后


props属性

props属性的用法和params属性都差不多,都是要在src/router/index.js文件中配置,我就不过多展示例子了。


	name:'XXX',
	path:'XXXxxx',
	component:xxx,

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

	//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给路由组件
	// props:true
	
	//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给路由组件
	props(route)
		return 
			id:route.query.id,
			name:route.query.name
		
	


replace属性

replace属性的作用是控制浏览器的操作历史记录的模式

浏览器的历史记录有两种写入方式:
push: 追加历史记录,即在前一条的记录上在新加一条浏览记录
replace: 覆盖历史记录,即在添加新记录的同时回收原有记录,替换掉原有记录

浏览器默认默认状态下是为push模式

开启replace模式:

<!-- 只需要在标签内加上replace属性即可实现 -->
<router-link replace .......>跳转</router-link>

编程式路由导航

在实际生活中,我们在浏览某些页面的时候会看见一些比如 下一步返回 之类的按钮,而这些按钮并不是导航原本具有的,但却实现了页面跳转的功能,其实在Vue中,也给我们准备了两个函数,只需调用这两个函数,即可实现页面的前进和后退,无需借助导航来切换,也简化了我们开发中的代码操作

this.$router.back()    //实现的功能就是后退
this.$router.forward()    //实现的功能就是前进

这个理解起来比较简单,就是记录你的浏览记录,假若是刚进入网站,在第一个页面,点击前进肯定是没反应的,所以,编程式路由导航起到的就是辅助性作用


路由缓存

路由组件中的缓存也是实际开发中比较常用的一个技巧,体现在用户在一个页面输入表单信息,当切换出这个页面再次返回时,组件还能保留用户输入的内容,让不展示的组件保持挂载,不需要再次挂载,这样的好处就是增强了页面与用户之间的交互性

其实只需要在<router-link>标签外再包裹上一层<keep-alive>标签即可

<!-- 这里的include属性是指指定的组件缓存,如果不加这个属性,也就意味着所有路由组件都缓存 -->
<keep-alive include="News"> 
   <router-view></router-view>
</keep-alive> 

具体代码:

改动部分:

TestB.vue:

<template>
  <div>
    <h4>我是内容二</h4>
    <!-- 多级路由 -->
    <div class="box">
      <!-- 此处路径一定要写完整路径 -->
      <!-- <router-link to="/TestB/TestBHzw" active-class="active">点击查看《海贼王的简介》</router-link>&nbsp;&nbsp;&nbsp;
      <router-link to="/TestB/TestBHyrz" active-class="active">点击查看《火影忍者的简介》</router-link> -->
      
      <router-link to="/TestB/TestBHyrz" active-class="active">点击查看《火影忍者的简介》</router-link>&nbsp;&nbsp;&nbsp;
      <!-- 路由缓存 -->
      <router-link to="/TestB/TestBHzw">填写信息</router-link>
      <hr>
      <keep-alive include="TestBHzw">
        <router-view></router-view>
      </keep-alive>
      
    </div>
  </div>
</template>

<script>
export default 
    name:'TestB',

</script>

<style scoped>
h4
  text-align: center;

.box
  text-align: center;

a
  text-decoration: none;

.active:visited
  color: brown;

</style>

TestBHzw.vue:

<template>
  <div>
    姓名:<input type="text"><br>
    性别:<input type="text"><br>
    年龄:<input type="text">
  </div>
</template>

<script>
export default 
    name:'TestBHzw'

</script>

<style>

</style>

值得注意的是:
如果我没有加<keep-alive>标签,那么当我信息填到一半切换路由,再次切换回来时,之前填的将不会保留

加上标签后,即便我来回切换,之前填的信息依然保留,可以继续往下填

但是,如果不限定include属性,则就是代表在此路由下的所有路由组件都会保持挂载,这样不利于提高性能,也没那个必要。用在该用的组件上就可以了


总结

以上知识点就是我对**Vue-Router(路由)**的一个更深一层的学习和理解,虽然学习的不算太深,但我相信至少对于初学者而言,是一篇不错的学习笔记,希望在我自己提升的同时,也能帮助一些刚接触Vue的同学,到这里,我自己对Vue路由的学习算是告一段落啦,等自己把基础的学会了,在往更深一层学习吧

如果觉得还不错的话,记得点赞收藏哟!!!
别忘了给我关注呀!!!

Vue-Router的使用详解

认识路由

渲染 & 路由

后端渲染 & 前端渲染

  • 后端渲染:在浏览器内输入地址,浏览器就可以展示一个页面,而页面内容展示的数据在后台服务器那边就已经渲染好了,浏览器只需要对返回的HTML做一个渲染就行了。
  • 前端渲染:在浏览器内输入地址,浏览器返回的是一些静态资源文件,内容里面的数据,由浏览器执行脚本,向服务器发送请求,浏览器拿到数据后,浏览器再渲染的页面上。

后端路由 & 前端路由

  • 后端路由:URL(唯一资源地址符),一个URL对应一个页面,浏览器地址栏的地址由服务器(后端)来处理URL和页面之间的映射关系。
  • 前端路由:URL和页面之间的映射关系由前端来处理。

URL的hash & HTML5的History

URL的hash

  • url的hash(锚点 # ):URL地址 # 后面的东西。
  • 改变hash不会引起页面的刷新,因为:hash会出现在url内,但是不会出现在HTTP请求中。
  • 点击浏览器页面刷新,会重新请求资源。

HTML5的History

  • HTML5的history模式,也不会引起页面的刷新。
  • history利用了浏览器的 历史记录栈,将每页面的信息放入的栈中。
  • 通过api对栈进行操作和展示浏览器显示的页面。
  • APIpushState、popState、replaceState、go、forward、back

使用 vue-router

基本使用

  • 安装:npm install vue-router@4
  • 配置映射关系:

image-20210707095311905

  • 注册路由

    将路由文件内导出的router在main.js内注册

import { createApp } from 'vue'
import App from './App.vue'
import router from "./router/index";
createApp(App).use(router).mount('#app')
  • 使用

    配置关系设置好了,注册完成,在使用时设置对应的路径,就会展示对应的组件页面出来。

    提供了内部组件:router-link(配置要跳转的路径)和router-view(占位标签,页面就在这里展示)。

<template>
  <div class="app">
    <router-link to="/home">首页</router-link>
    <router-link to="/about">关于</router-link>
    <router-view></router-view>
  </div>
</template>

其他小补充

  • meta添加信息。
{
    path: '/about',
    component: About,
    meta: {
        address: '湖南',
        university: '湖南中医药大学'
    }
}

先知道可以这样,后面会说到怎么取到其中的内容。

  • 重定向redirect。本来默认下页面打开就应该直接跳到主页,但是就上面配置还需手动点击才行,解决这个小问题,配置重定向。

    routes 内增加一个映射:

    {
      path: '/',
      redirect:'/home'
    }
    
  • history模式:将 createWebHashHistory()改为createWebHistory()

router-link属性

  • to
    • 字符串:要跳转的路径。
    • 对象:跳转和传参。
<template>
  <div class="app">
    <router-link to="/home">首页</router-link>
    <router-link :to="{ path:'/about', query:{name:'fzb',age:18}}">关于</router-link>
    <router-view></router-view>
  </div>
</template>
  • replace在history模式下默认是pushState的,设置 replace 转换成replaceSatate
  • active-class不设置此属性,默认条件下对应跳转页面的元素增加的类是 router-link-active。太复杂了不好记,使用 active-class设置自定义类名。
  • exact-active-class默认是 router-link-exact-active,这个是浏览器地址栏的路径和页面映射路径完全一致是才设置对应的class。太复杂了不好记,使用 exact-active-class设置自定义类名。

路由懒加载 (常用)

假如开发的时候,在配置映射关系时的component直接是像上面一样导入,那么打包后会打包到同一个js文件内。

其实这样不好,会增加首屏渲染时间,用户体验下降,其实可以其他页面在没有点开过就不需要加载。

如下操作:

// 改写成未注释写法
// import Home from "../page/Home.vue";
// import About from "../page/About.vue";

const Home = () =>
    import ('../page/Home.vue');
const About = () =>
    import ('../page/About.vue');

小补充webpack知识:魔法注释

设置自定义打包名

image-20210707105403993

动态路由

基本使用

image-20210707110510942

获取动态路由的值

  • template标签
<h2>{{$route.params.userid}}</h2>
  • options API中,通过 this
computed:{
  userId(){
    return this.$route.params.userid
    }
}
  • composition API中,是没有 this 的。
<script>
import { useRoute } from "vue-router";
export default {
  setup(){
      const routr = useRoute();
      const userId = routr.params.userid
      return {
          userId
      }
  }
}
</script>

匹配多个参数

匹配模式路径匹配$route.params
/user/:userid/user/0240{ “userid”: “0240” }
/user/:name/:userid/user/fzb/0240{ “name”: “fzb”, “userid”: “0240” }
/user/:name/id/:userid/user/fzb/id/0240{ “name”: “fzb”, “userid”: “0240” }

NotFound

在地址栏输入路径,没有匹配到,显示的页面。

image-20210707112708698

同样可以获取到路径内的信息。

image-20210707113014429

细节:pathMatch(.*)后加不加*

匹配模式路径匹配$route.params.pathMatch
/:pathMatch(.*)/home/111/home/111
/:pathMatch(.*)*/home/111[ “home”, “111” ]

路由的嵌套

配置

{
    path: '/home',
    component: Home,
    redirect: '/home/message',
    children: [{
        path: 'message',
        component: () = >import('../page/HomeMessage.vue')
    },
    {
        path: 'goods',
        component: () = >import('../page/HomeGoods.vue')
    }]
}

在Home.vue内增加router-linkrouter-view就可以了。

代码实现路由跳转

  • template
<button @click="$router.push('/home')">首页</button>
  • option API
<script>
export default {
  name: 'App',
  methods:{
    btnClic(){
      this.$router.push('/home')
    }
  }
}
</script>
  • composition API
<script>
import { useRouter } from "vue-router";
export default {
  name: 'App',
  setup(){
    const router =  useRouter();
    const btnClic = ()=> {
     router.push('/home')
    }
    return{
      btnClic
    }
  }
}
</script>

除了router由push方法外,还有pop、replace、go、back、forward方法。

query方式的参数

发送

<router-link :to="{ path:'/about', query:{name:'fzb',age:18}}"  active-class="fzb">关于</router-link>

或者

this.$router.push({
    path: '/home',
    query: {
        name: 'fzb',
        age: 18
    }
})

接收

  • template直接接收使用
<h2>$route.query</h2>
  • option API使用
this.$route.query
  • composition API 使用
<script>
import { useRoute } from "vue-router";
export default {
  setup(){
    const route = useRoute();
    const querys = route.query;
    return{
      querys
    }
  }
}
</script>

router-link的补充

在vue-router3.x的时候,router-link内有一个属性 tag 默认条件下,router-link会渲染成一个a标签,当设置其他标签的名字(包括组件名)都会渲染成相应标签。

router-link的插槽

  • 标签内设置custom属性,表自定义router-link。

  • 作用域插槽v-slot返回一个对象,对象内的值说明:

    • navigate:一个函数。指定渲染目标标签,须同时设置navigatecustom
    • href:跳转目标的路径。
    • route:目标页面的路由对象。
    • isActive:路径是否匹配的状态。
    • isExactActive:路径是否是精准匹配的状态;

router-view的补充

router-view的插槽

  • 作用域插槽v-slot返回一个对象,对象内的值说明:
    • Component:要渲染的组件
    • route:解析出的标准化路由对象

直接点击按钮,页面切换,太生硬,结合transition使用。

image-20210707142820546

动态添加路由

根据不同的权限,注册不同的路由,并不是注册死的路由。

  • 动态添加一级路由addRouter方法

    拿到 router 对象

const addOneRoute = {
    path: '/first',
    component: () =>
        import ('../page/AddOneRoute.vue')
}
router.addRoute(addOneRoute);
  • 动态添加二级路由addRouter方法

    第一个参数传入父级映射的 name属性。

const addOneRoute = {
    path: 'next',
    component: () =>
        import ('../page/AddOneRoute.vue')
}
router.addRoute('parentName', addOneRoute);

删除路由

  • 添加一个name相同的路由;
router.addRoute({path:'/category',name:'category',component:Category});
// 会将上面的路由覆盖掉
router.addRoute({path:'/other',name:'category',component:Other});
  • 删除路由方法removeRoute
router.addRoute({ path: '/category', name: 'category', component: Category });
router.removeRoute('category');
  • 删除路由函数addRoute后返回函数
const remove = router.addRoute({ path: '/category', name: 'category', component: Category });
//调用addRoute后返回的值,是一个函数,直接调用,删除路由。
remove();

其他方法

  • router.hasRoute():检查路由是否存在。
  • router.getRoutes():获取一个包含所有路由记录的数组。

路由守卫

在进行跳转前,可以进行拦截,可以进行一些操作。

全局守卫

  • 前置守卫 router.beforeEach(( to, from )=>{ ..... return xxx })

    • to:要进入的路由

    • from:当前导航要离开的路由

      每次跳转都会调用

    返回值情况分类

    返回值类型(return的类型)对应的操作
    字符串(’/home’)导航到 路径为 /home 对应的页面
    undefined或不写返回值默认跳转
    false不进导航
    对象类似于router.push({path: ‘/about’ , query:{ name:‘fzb’}})

接下来的我也不是很了解,用到是在去查,提供链接

路由独享的守卫守卫

在配置映射关系的对象内配置路由独享守卫:beforeEnter,接收 tofrom两参数,参数意思与上方一致。

组件内守卫

在组件内定义的守卫,和option API一样是一个选项。

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave

在这里插入图片描述

文章看了,动画看了,如果客官觉得可以,三连支持一下吧。(确实写了挺久的)

以上是关于Vue路由(router)进一步详解的主要内容,如果未能解决你的问题,请参考以下文章

Vue-Router

如何使用Vue.js中的路由vue-router创建单页应用

Vue路由(router)进一步详解

vue3实践---路由router

Vue-vue-router.js路由

vue.js路由vue-router——简单路由基础