route
)是一组映射关系(key:value
)。SPA
应用)。router
)进行管理。第一步:参考
about.html
或home.html
,把App
结构写好。第二步:编写两个组件:
About.vue
、Home.vue
第三步:找到
App
中的导航区、展示区,熟悉一下它们位置。
安装vue-router
,命令:npm i vue-router@3
备注:在
vue2
中要用vue-router@3
,vue3
中要用vue-router@4
。
创建src/router/index.js
,配置路由器:
// 该文件主要用于:创建并暴露一个真正的路由器
import Vue from 'vue'
// 引入VueRouter
import VueRouter from 'vue-router'
// 安装VueRouter插件
Vue.use(VueRouter)
// 创建并暴露一个路由器
export default new VueRouter({})
创建vm
时传入路由器配置(操作的是:src\main.js
)
import Vue from 'vue'
import App from './App'
//引入路由器
import router from './router'
Vue.config.productionTip = false
new Vue({
el:'#root',
render: h => h(App),
router //此处传入路由器
})
路径中出现#
,开发者工具中有Routes
选项,所有的vc
和vm
身上均有了$router
和$route
,就是配置成功了。
在src/router/index.js
,配置路由规则:
import Home from '@/components/Home'
import About from '@/components/About'
// 创建并暴露一个路由器
export default new VueRouter({
//routes中配置一组一组的路由规则
routes:[
{ path:'/about',component:About },
{ path:'/home',component:Home }
]
})
跳转路由
<router-link class="list-group-item" to="/about">
About
router-link>
指定展示位置
<router-view>router-view> 或 <router-view/>
history(美观,兼容性略差,后期上线部署时,服务器要做对应处理)—— 前台项目推荐使用。
hash(不美观,带#
,但兼容性较好)—— 一般后台管理系统推荐使用。
如何配置? —— 创建路由器的时候添加一个mode
属性
let router = new VueRouter({
mode:'history', //常用值:history、hash
//....
})
使用active-class
可以指定高亮的类名
<router-link class="list-group-item" active-class="xxxxxx" to="/about">
About
router-link>
<router-link active-class="active" to="/about">Aboutrouter-link>
<router-link active-class="active" :to="{path:'/about'}">Aboutrouter-link>
路由组件通常存放在pages
或 views
文件夹,一般组件通常存放在components
文件夹。
通过点击导航,视觉效果上“消失” 了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
编写Home
的两个子组件:News.vue
、Message.vue
配置路由规则,使用children
配置项:
/*******/
{
path:'/home',
component:Home,
//通过children配置子级路由
children:[
{
path:'news', //此处要写news!不是/news,
component:News
},
{
path:'message',//此处要写message!不是/message,
component:Message
}
]
}
/*******/
跳转路由(记得要加完整路径):
<router-link to="/home/news">Newsrouter-link>
<router-link :to="{path:'/home/news'}">Newsrouter-link>
记得去Home
组件中预留一个
<template>
<div>
<h2>我是Home的内容h2>
<ul class="nav nav-tabs">
<li>
<router-link to="/home/news">Newsrouter-link>
li>
<li>
<router-link to="/home/message">Messagerouter-link>
li>
ul>
<div>
<router-view/>
div>
div>
template>
当出现子级路由时,刷新页面会造成第三方样式丢失的问题,三种解决方案如下:
public/index.html
中引入样式时的路径修改一下,将 ./
改为 /
。(最推荐)public/index.html
中引入样式时的路径修改一下,将 ./
改为 <%= BASE_URL %>
。(推荐)hash
模式(不推荐)可以简化:路由跳转、路由传参(接下来就要讲了)。
具体使用步骤:
给路由命名:
const router = new VueRouter({
mode:'history',
//routes用于配置一组一组的路由规则
routes:[
{
name:'guanyu',
path:'/about',
component:About
},
{
name:'zhuye',
path:'/home',
component:Home,
children:[
{
name:'xinwen',
path:'news',
component:News
},
{
name:'xiaoxi',
path:'message',
component:Message,
}
]
}
]
})
跳转路由:
跳转
跳转
组件实例的$route
属性:存储着当前路由信息(路径、参数、规则名字…后期会用到这里很多的属性)。
组件实例的$router
属性:整个应用的路由器,后期可以通过它 控制路由跳转。
Detail
组件。Message
组件中编写:router-link
和router-view
。传递参数
<!-- 跳转并携带query参数(to的字符串写法) -->
<router-link to="/home/message/detail?a=1&b=2&content=欢迎你">
跳转
</router-link>
<!-- 跳转并携带query参数(to的对象写法) -->
<router-link
:to="{
//name:'xiangqing', //用name也可以跳转
path:'/home/message/detail',
query:{
id:m.id,
title:m.title,
content:m.content
}
}"
>
{{m.title}}
</router-link>
接收参数:
this.$route.query.xxx
query
参数,没什么坑,唯一要注意的是:参数的值尽可能别是对象;参数若是对象,跳转传递时没问题,但会造成刷新时参数变为[object Object]
。- 备注:路由组件初次呈现是挂载,后期参数发生变化会更新。
第一步:在路由规则中,声明接收params
参数:
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News
},
{
component:Message,
children:[
{
name:'xiangqing',
path:'detail/:id/:title/:content',
component:Detail
}
]
}
]
}
第二步:传递params
参数
<router-link :to="`/home/message/detail/${m.id}/${m.title}/${m.content}`">
{{m.title}}
router-link>
<router-link
:to="{
name:'xiangqing',
params:{
id:m.id,
title:m.title,
content:m.content
}
}"
>
{{m.title}}
router-link>
第三步:读取参数
this.$route.params.xxx
传递params
参数时,必须提前占位,且要注意顺序与个数,但若用的是to
的对象写法,那顺序无所谓了。
注意:顺序不能乱、个数不能多、也不能少。可以用?控制必要性,默认是必须的
传递params
参数时,若使用to
的对象写法,必须使用name
配置项,不能用path
。
<router-link
:to="{
name:'xiangqing',
params:{
id:m.id,
title:m.title,
content:m.content
}
}"
>跳转router-link>
占位时,可以通过?
可以控制params
参数的必要性。
{
//含义:title三个参数可传、也可不传。
path:'detail/:id/:title?/:content?',
component:Detail
}
参数的值不能是对象,不能是空字符串、不能是数组。
作用:让路由组件更方便的收到参数(可以将路由参数作为props传给组件)
{
name:'xiangqing',
path:'detail/:id/:title/:content',
component:Detail,
// props的对象写法,作用:把对象中的每一组key-value作为props传给Detail组件
// props:{a:1,b:2,c:3},
// props的布尔值写法,作用:把收到了每一组params参数,作为props传给Detail组件
// props:true
// props的函数写法,作用:把返回的对象中每一组key-value作为props传给Detail组件
props($route){
return $route.query
}
}
作用:让不展示的路由组件保持挂载,不被销毁。
具体编码:
<keep-alive :include="['News','Message']">
<router-view>router-view>
keep-alive>
<keep-alive include="News">
<router-view>router-view>
keep-alive>
<keep-alive exclude="News">
<router-view>router-view>
keep-alive>
<keep-alive>
<router-view>router-view>
keep-alive>
作用:控制路由跳转时操作浏览器历史记录的模式。
浏览器的历史记录有两种写入方式:分别为push
和replace
:
push
是追加历史记录(默认值)。replace
是替换当前记录。如何开启replace
模式:
<router-link replace .......>Newsrouter-link>
作用:不借助
实现路由跳转,让路由跳转更加灵活
- 靠非click事件 或 靠一些逻辑触发跳转 —— 此时就需要编程式路由跳转
- 最终呈现的元素不是a元素,此时就需要编程式路由跳转
$router.push
、$router.replace
。$router.forward
$router.back
具体编码:
// $router的两个API
this.$router.push({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
// 备注:push和to属性的使用方式一样,也可以传递字符串,例如:this.$router.push('/about')
this.$router.replace({
name:'xiangqing',
params:{
id:xxx,
title:xxx,
content:xxxx
}
})
问题描述:编程式路由导航,若重复跳转会抛出: NavigationDuplicated 的错误。
问题原因:
vue-router 3.1.0
之后,编程式路由导航内部使用了Promise
语法。Promise
实例。Promise
实例状态为失败;Promise
实例状态为成功;解决办法:
办法一:指定成功 或 失败的回调函数(成功回调、失败回调同时都指定也可以),代码如下:
this.$router.replace('/search',()=>{})
办法二:使用catch
处理错误,代码如下:
this.$router.replace('/search').catch(() => {})
办法三:见下面
需求:对数组的push
方法做增强,让push
进去的数字,比写的数字大1
。
具体实现:
//将Array原型上的push方法备份一份
const originPush = Array.prototype.push
//修改push方法为我们写的方法
Array.prototype.push = function(value){
value += 1
return originPush.call(this,value)
}
修改 VueRouter
原型上的push
和 replace
方法 (推荐)
//将VueRouter原型上的push和replace保存一份
const originPush = VueRouter.prototype.push
const originReplace = VueRouter.prototype.replace
//修改VueRouter原型上的push,用于解决重复跳转报错
VueRouter.prototype.push = function(location,onSuccess,onError){
if(onSuccess || onError){
return originPush.call(this,location,onSuccess,onError)
}else{
return originPush.call(this,location).catch(()=>{})
}
}
//修改VueRouter原型上的replace,用于解决重复跳转报错
VueRouter.prototype.replace = function(location,onSuccess,onError){
if(onSuccess || onError){
return originReplace.call(this,location,onSuccess,onError)
}else{
return originReplace.call(this,location).catch(()=>{})
}
}
//优化封装
function enhance (name,source){
// 将VueRouter原型上原始的push保存一份
const origin = source.prototype[name]
// 修改VueRouter原型上的push
source.prototype[name] = function(location,onSuccess,onError){
if(onSuccess || onError){
return origin.call(this,location,onSuccess,onError)
}else{
return origin.call(this,location).catch(()=>{})
}
}
}
enhance('push',VueRouter)
enhance('replace',VueRouter)
作用:将特定的路径,重新定向到已有路由。
具体编码:
{
path:'/',
redirect:'/about'
}
注意:
redirect
要写完整。path
可以直接写其父级、或留空。- 子级路由若配置重定向,则其父级最好去掉
name
配置项,否则通过name
跳转时,默认子路由不呈现。
路由跳转时当参数值为undefine时,会在路径上不显示参数
data() {
return {
keyword: "" || undefined,
};
},
this.$router.push({
path: "/search",
query: {
...query,
keyword: this.keyword,
},
});