这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战
前言
学完Vuex方面的操作就该来学学Vue中的路由操作了.... xdm冲
一、安装
vue-cli 安装
vue add router
做完这一步基础环境都搭好了。
项目中会多一个
文件夹,内容如下:
最后暴露出来,在mian.js 中引用进去就可以了。暂时先不细讲。
二、基本路由使用
基本路由使用,其实你安装完就已经有例子啦。
在App组件中 有下面这两行代码,其实就路由跳转的意思。
<router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> |
我们以前是用a标签,这里只是帮我们封装了。这里配置好的/
及/about
都是router文件夹下配置好的路由规则
,每个路径和哪个组件相对应。
效果如下:
点击就能跳转.
这是最基础的,看看就完事了,因为咱们使用这种方式挺少的,基本上在路由跳转的过程中都是要做很多事情的.
但是大家发现了没有,只有内容变了,为啥呢?
因为app组件中 <router-view/>
这个代码,意思就是切换路由时,将组件内容放到这里展示。
这最基本的,大家随便玩玩都会的,咱们不多说。
问个小问题,这个路由跳转的过程中,原来的哪个组件是被隐藏了,还是销毁了呢???
三、嵌套路由(套娃)
效果图:
就是在home和about下分别来个路由,也非常容易。
我们先加两个组件
我们再router
中进行配置一下。
const routes = [ { path: '/', name: 'Home', component: Home, children: [ { path: '/message', name: 'message', component: () => import(/* webpackChunkName: "about" */ '../components/Message.vue'), } ] }, { path: '/about', name: 'About', component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), children: [ { path: '/news', name: 'news', component: () => import(/* webpackChunkName: "about" */ '../components/News.vue'), }, ] } ]
其实也就牵扯到children
这一个属性,就是和上级路由形成父子关系啦。套娃两层是这么套,那么套再多就是在里面接着写就完事了。
一次套娃一次爽,一直套娃一直爽
四、路由传参
效果
我们再加一个两个子路由,在里面实现路由传参。另外把原来的组件改一下。
4.1、搭建基础环境
MessageItem组件
<template> <div> <p>消息编号:???<//p> <p>消息标题:???<//p> </div> </template>
NewsItem组件
<template> <div> <p>新闻编号:???</p> <p>新闻标题:???</p> </div> </template> <script>
这里的???是稍后用来接收路由传参的哈。
News组件
<template> <div> <ul> <li v-for="newItem in news" :key="newItem.id"> <router-link to="/item">{{newItem.id}}:{{newItem.title}}</router-link> </li> </ul> <router-view></router-view> </div> </template> <script> export default { data(){ return { news:[ {id:1, title:"001新闻"}, {id:2, title:"002新闻"}, {id:3, title:"003新闻"} ] } } } </script>
Message组件
<template> <div> <ul> <li v-for="message in messages" :key="message.id"> <router-link to="/item">{{message.id}}:{{message.title}}</router-link> </li> </ul> <router-view></router-view> </div> </template> <script> export default { data(){ return { messages:[ {id:1, title:"001信息"}, {id:2, title:"002信息"}, {id:3, title:"003信息"} ] } } } </script>
4.2、query参数
第一种:to 的字符串写法
URL传参,组件用$route.query
取值
Message组件
<li v-for="message in messages" :key="message.id"> <router-link :to="`/item?id=${message.id}&title=${message.title}`">{{message.id}}:{{message.title}}</router-link> </li>
注意
这里的 to
前面是加了引号的,并且中间的 内容也是用 **`**符号修饰的
MessageItem组件
<div> <p>消息编号:{{$route.query.id }}</p> <p>消息标题:{{$route.query.title }}</p> </div>
第二种:to的对象方法
<li v-for="message in messages" :key="message.id"> <!-- to的字符串写法 --> <!-- <router-link :to="`/item?id=${message.id}&title=${message.title}`">{{message.id}}:{{message.title}}</router-link> --> <!-- to的对象写法 --> <router-link :to="{ path: '/item', query: { id: message.id, title: message.title } }">{{message.id}}:{{message.title}}</router-link> </li>
另外一边接收的方式还是同上。
4.3、params参数
第一种:to的字符串写法
跳转链接还是差不多的,但是必须在路由规则中进行配置
<router-link :to="`/item/${message.id}/${message.title}`">{{message.id}}:{{message.title}}</router-link>
{ path: '/', name: 'Home', component: Home, children: [ { path: '/message', name: 'message', component: () => import(/* webpackChunkName: "about" */ '../components/Message.vue'), children: [ { path: '/item/:id/:title', // 使用占位符声明接收params参数 name: 'messageItem', component: () => import(/* webpackChunkName: "about" */ '../components/MessageItem.vue') } ] } ] },
接收的也稍稍有变化:
<p>消息编号:{{$route.params.id }}</p> <p>消息标题:{{$route.params.title }}</p>
第二种:to的对象写法
<!-- to的对象写法 --> <router-link :to="{ name: 'messageItem', params:{ id:message.id, title: message.title } }"> {{message.id}}:{{message.title}}</router-link>
注意
:这里必须用 name
,即配置好的路由名称,不能够使用路由路径。
4.4、路由的props配置(偷懒的好工具)
我们思考一个问题哈。
你有没有觉得{{$route.params.id }}
或者{{$route.params.title }}
这样子去取一个路由传过来的值,十分重复呢???
取每个值,都还要写一遍$route.params
或者是$this.query
这个前缀,有没有觉得十分重复,那么有没有更简单的呢?
(一个两个还是简单的,万一有天传的多了,这个props肯定是能偷懒的哈🐥)
1)props配置方式一:
{ path: '/', name: 'Home', component: Home, children: [ { path: '/message', name: 'message', component: () => import(/* webpackChunkName: "about" */ '../components/Message.vue'), children: [ { path: '/item/:id/:title', name: 'messageItem', component: () => import(/* webpackChunkName: "about" */ '../components/MessageItem.vue'), //第一种方式:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给MessageItem组件 props:true } ] } ] },
传递 params 参数的父组件啥都不用改,
我们改一下接收的子组件
<template> <div> <!-- <p>消息编号:{{$route.query.id }}</p> <p>消息标题:{{$route.query.title }}</p> --> <!-- <p>消息编号:{{$route.params.id }}</p> <p>消息标题:{{$route.params.title }}</p> --> <!-- 通过props 接收 --> <p>消息编号:{{id }}</p> <p>消息标题:{{title }}</p> </div> </template> <script> export default { props:['id','title'] } </script>
2)props配置方式二:
思考一下,上面的那个方法只能解决传递params参数时进行缩写,那么如果是传递query参数方式该怎么办呢?
props 配置其实可以改成一个函数的哈
注意:记得在练习的时候,
{ path: '/', name: 'Home', component: Home, children: [ { path: '/message', name: 'message', component: () => import(/* webpackChunkName: "about" */ '../components/Message.vue'), children: [ { path: '/item', name: 'messageItem', component: () => import(/* webpackChunkName: "about" */ '../components/MessageItem.vue'), // props:true //第二种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给MessageItem组件 props($route) { return { id: $route.query.id, title: $route.query.title } } } ] } ] },
想接收什么,我们就是在这边写啥就完事了,到了子组件,就是直接用了。
解构写法
props({query}) { return { id: query.id, title: query.title } }
更偷懒的就是连续解构:
props({query:{id,title}}) { return {id,title} }
果然是偷懒使人进步啊。
五、编程式路由
5.1、编程式实现路由跳转
之前我们都是借助 <router-link to="/news">新闻</router-link>
这个来实现路由的跳转,但实际开发中都是通过点击按钮或者是触发什么事件,然后才进行跳转的,所以使用router-link
并不是特别合适。才有了编程式路由。
<li v-for="message in messages" :key="message.id"> <router-link :to="{ path: '/item', query: { id: message.id, title: message.title, }, }" > {{ message.id }}:{{ message.title }}</router-link > | <button type="button" @click="showMessageItem( message.id, message.title,)"> 点击跳转到{{ message.title }}页面 </button> </li>
利用方法进行跳转
methods: { showMessageItem(id,title){ this.$router.push( { path: '/item', query: { id: id, title:title } }) } }
如果是params 也是和之前一样的;
showPamarsMessageItem(id,title){ this.$router.push( { name: 'messageItem', params: { id: id, title:title } }) }
相关的信息也要改哈,路由中配置的props啥的。
5.2、编程式控制前进后退
对于浏览器中的前进后退按钮,我们大家肯定是不陌生哈。
其实这个也是可以用编程式的方式来实现的。
<template> <div id="app"> <button id="back" @click="back">后退</button> | <button id="forward" @click="forward">前进</button> | <button id="forward" @click="go">go</button> <div id="nav" > <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> | </div> <router-view/> </div> </template> <script> export default { methods: { back(){ console.log(this.$router) this.$router.back() }, forward(){ this.$router.forward() }, go(){ //直接说这个go () 的参数是一个数字 ,正数就是前进多少步, // 负数就是回退多少步。 this.$router.go(2) } } } </script>
其实都是通过$router
上的api来实现的,但是如果是无痕状态下,还是无法实现的,因为这些实现还是需要依靠浏览器的历史记录的。
效果图:
六、缓存路由组件
作用:让不展示的路由组件保持挂载,不被销毁。
我们在MessageItem组件中写上一个beforeDestroy
销毁之前的钩子函数
<template> <div> <p>消息编号:{{ id }}</p> <p>消息标题:{{ title }}</p> </div> </template> <script> export default { name: 'MessageItem', props:['id','title'], beforeDestroy(){ console.log('MessageItem组件被销毁了') } } </script>
当我们从MessageItem组件切换到其他页面时,就会打印出这个。
但是如果我们在使用他的父组件身上改成下面这样的。
<keep-alive include="MessageItem"> <router-view></router-view> </keep-alive>
注意
:include
中写的是组件名。组件名。组件名。
如果不写include,是默认全部都缓存,不销毁。
这样写就会保证MessageItem在切换的过程中不会被销毁。
如果切换的异常频繁的话,我觉得加上这个还是可以的。
七、两个新的生命周期钩子函数
在第六小节,我们可以把组件进行缓存,但是同时也会造车组件的beforeDestroy
生命周期钩子函数失效。
那么有些清除操作将会没法执行(如切换路由,让定时器暂停),所以就有了两个路由的独有的生命周期钩子函数。
activated
路由组件被激活时触发。deactivated
路由组件失活时触发。
activated(){ console.log('MessageItem被激活了') }, deactivated(){ console.log('MessageItem失活了') }
后语
大家一起加油!!!如若文章中有不足之处,请大家及时指出,在此郑重感谢。
纸上得来终觉浅,绝知此事要躬行。
一名喜欢文艺却踏上编程这条道路的小青年。
希望:
我们,待别日相见时,都已有所成
。
一方面是老师要求学习,另外一方面也是这次活动,两者的碰撞,好好的让我系统的学习了一遍前端vue,以及在学习的过程中还复习了一遍JavaScript及CSS知识.于我个人而言,这个月的收获是非常充实的。
于我而言,对于Vue的学习还在刚刚开始,对于前端
这个领域,我更像是莽撞且无知的小白。
期待许久的年终终结,它来了,有太多太多想说没有说的话,希望发在这个没有人认识自己的地方,能够得到一些别样的收获吧。
谢谢你,能够看到这里。