这篇文章主要讲路由跳转和路由传参,声明式导航和编程式导航的跳转和传参的区别,开始先回顾配置路由的几个步骤。
一、使用路由的4步
定义路由组件
注册路由
引入路由
路由跳转
1) 定义路由组件
src/pages/Home/index.vue
src/pages/Login/index.vue
2) 配置路由/ 注册路由
src/router/index.js
// 配置路由的地方
import Vue from 'vue'
import VueRouter from 'vue-router'
// 使用插件
Vue.use(VueRouter)
// 引入路由组件
import Home from '@/pages/Home'
import Login from '@/pages/Login'
// 配置路由
export default new VueRouter({
routes: [
{
path: '/home',
component: Home
},
{
path: '/login',
component: Login
},
// 重定向在项目跑起来的时候,访问/,立马让它定向到首页
{
path: '*', // 或者 path: '/'
component: Home
},
]
})
3) 使用路由(文件夹),入口文件引入和注册路由
- main.js
import Vue from 'vue'
import App from './App.vue'
// 引入路由
import router from '@/router'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
// 注册路由:底下的写法KV一致省略V【router小写的】
// 注册路由信息:当这里书写router的时候。组件身上都拥有$route,$router属性
router
}).$mount('#app')
4)路由跳转
- App.vue
<template>
<div>
<!-- 路由组件出口的地方 -->
<router-view></router-view>
</div>
</template>
以上四步就可以实现在地址栏手动输入路由展示对应的路由组件
路由组件和非路由组件的区别
1.路由组件一般放置在pages或者views文件夹,非路由组件一般放置在components文件夹中
2.路由组件一般需要在router文件夹中进行注册
3.注册完路由,不管路由组件还是非路由组件身上都有 r o u t e 和 route和 route和router属性
$route和$router
$route:一般获取路由信息【路径、query、params等等】
$router:一般进行编程式导航进行路由跳转【push|replace】
二、路由的跳转
声明式导航:声明式导航能做的,编程式导航都能做
编程式导航:除了可以进行路由跳转,还可以做一些其他的业务逻辑
声明式导航
例子:原本a标签跳转改成router-link跳转,必须要有to属性注意样式还在
- 例1
<a href="###">登录</a>
改成
<router-link to="/login">登录</router-link>
- 例2
target是打开新的网页
<a class="logo" href="###" title="尚品汇" target="_blank">
<img src="./images/logo.png" alt="" />
</a>
改成声明式路由导航
<router-link class="logo" to="/home">
<img src="./images/logo.png" alt="" />
</router-link>
编程式导航
- 比如元素上加点击事件
<div @click="gotoSearch()">跳转</div>
gotoSearch() {
this.$router.push(/search)
}
三、路由元信息
可以根据组件身上的$route获取当前路由的信息,通过路由路径判断Footer显示和隐藏
配置路由的时候,可以给路由添加路由元信息【meta】,路由需要配置对象,它的key不能乱写
- router/index.js
routes: [
{
path: '/home',
component: Home,
meta: {show:true}
},
{
path: '/login',
component: Login,
meta: {show:false}
},
...
]
- App.vue
Header组件和Footer组件 都是非路由组件
<template>
<div>
<Header />
<!-- 路由组件出口的地方 -->
<router-view></router-view>
<!-- 在Home与Search可见的,但是Login|Register不可见 -->
<!-- 利用路由元信息解决当前问题好处:一行代码就可以解决 -->
<Footer v-show="$route.meta.isShow" />
</div>
</template>
四、路由传参
params参数:路由需要占位,属于URL当中一部分
query参数:路由不需要占位,写法类似于ajax当中query参数,queryString /home?k=v&kv=,不需要占位
- demo效果
query参数–三种形式直接传
- views/Header/index.vue
<template>
<div>
<h3>Header组件</h3>
<input type="text" v-model="keyword" />
<button type="button" @click="goSearch">搜索</button>
</div>
</template>
<script>
export default {
data() {
return {
keyword: ''
}
},
methods: {
goSearch() {
// this.$router.push('/search') // 不传参
// 路由传递参数
// 第一种:字符串形式
// this.$router.push("/search/" + this.keyword + "?k=" + this.keyword.toUpperCase())
// 第二种:模板字符串
// this.$router.push(`/search/${this.keyword}?k=${this.keyword.toUpperCase()}`)
// 第三种:对象--常用
this.$router.push({name:'search', params: {keyword: this.keyword}, query: {k: this.keyword.toUpperCase()}})
}
}
}
</script>
- views/Search/index.vue
params参数–字符串形式和模板字符串–额外配置
- router/index.js配置路由时,加
/:keyword
{
path: '/search/:keyword',
component: Search,
meta: {show: true}
},
params参数–对象形式–额外配置
- router/index.js配置路由时,
加name
{
path: '/search',
component: Search,
meta: {show: true},
name: 'search'
},
- 如果没配置,会报错如下
五、路由传递参数相关面试题
1:路由传递参数(对象写法)path是否可以结合params参数一起使用?
2:如何指定params参数可传可不传?
3:params参数可以传递也可以不传递,但是如果传递是空串,如何解决?
4:如果指定name与params配置, 但params中数据是一个"", 无法跳转,路径会出问题
5: 路由组件能不能传递props数据?
1:路由传递参数(对象写法)path是否可以结合params参数一起使用?
答:路由跳转的时候,对象的写法可以是name、path形式,但是需要注意的是,path这种写法不能和params参数一起使用,不能这样书写,程序会崩掉
根据上面demo代码测试错误写法
this.$router.push({path:'/search', params: {keyword: this.keyword}, query: {k: this.keyword.toUpperCase()}})
报错如下
2:如何指定params参数可传可不传?
比如:配置路由的时候,占位了(params参数),但是路由跳转的时候就不传递。路径会出现问题
http://localhost:8080/#/?k=QWE
解决办法:如何指定params参数可以传递或者不传递,
在配置路由的时候,在占位的后面加上一个问号【params可以传递或者不传递】
- router/index.js配置路由时,在
/:keyword
后加?
{
path: '/search/:keyword?',
component: Search,
meta: {show: true}
},
- 效果:
http://localhost:8080/#/search?k=QWE
3:params参数可以传递也可以不传递,但是如果传递是空串,如何解决?
使用undefined解决,如果传递是空串,让传递的值变成undefined:params参数可以传递、不传递(空字符串)
this.$router.push({name:'search', params: {keyword: '' || undefined}, query: {k: this.keyword.toUpperCase()}})
4:如果指定name与params配置, 但params中数据是一个""
无法跳转,路径会出问题
5: 路由组件能不能传递props数据?
能(用得少)
布尔值写法(只能传递params参数)
- router/index.js配置路由时,加props: true,让props成为路由的属性
{
path: '/search/:keyword?',
component: Search,
meta: {show: true},
props: true,
},
- 接收的路由组件里
Search/index.vue
和普通组件接收一样,模板渲染使用{{keyword}}
props: ['keyword']
对象写法
- router/index.js配置路由时,加些额外参数
{
path: '/search/:keyword?',
component: Search,
meta: {show: true},
props: true,
props: {a:1, b:2}
},
- 接收的路由组件里Search/index.vue
props和普通组件接收一样,模板渲染使用{{keyword}} {{a}} {{b}}
props: ['keyword''a','b']
函数写法
可以将params、query参数,通过props传递给路由组件
props:($route) => {
return {keyword: $route.params.keyword, k: $route.query.k}
}
六、重写push和replace方法
理解
1.编程式导路由跳转到当前路由(参数不变),多次执行会抛出NavigationDuplicated的警告错误?
路由跳转有两种形式:声明式导航、编程式导航
声明式导航没有这类问题,因为vue-router底层已经处理好了
- 1.1为什么编程式导航进行路由跳转的时候,就会有这种警告错误?
原因:“vue-router”: “^3.5,3”,最新的vue-router引入promise
理解:
function push() {
return new Promise((resolve, reject) => {
})
}
所以我们需要给promise传入成功或者失败的状态,才能捕获这次的异常
- 1.2解决思路:通过push方法传递相应的成功、失败的回调函数,可以捕获到当前错误,可以解决。
- 1.3通过底部的代码,可以实现解决错误
this.$router.push({name:"search", params:{keyword: this.keyword}, query: {k: this.keyword.toUpperCase()}}, ()=> {}, ()=> {})
这种写法,治标不治本,将来在别的组件当中push|replace,编程式导航还是有类似错误。
- 1.4
this:是当前组件(search组件)实例
this. r o u t e r 属 性 : 当 前 的 这 个 属 性 , 属 性 值 V u e R o u t e r 类 的 一 个 实 例 , 当 在 入 口 文 件 注 册 路 由 的 时 候 , 给 组 件 实 例 添 加 router属性:当前的这个属性,属性值VueRouter类的一个实例,当在入口文件注册路由的时候,给组件实例添加 router属性:当前的这个属性,属性值VueRouter类的一个实例,当在入口文件注册路由的时候,给组件实例添加router| r o u t e 属 性 控 制 台 打 印 c o n s o l e . l o g ( t h i s . route属性 控制台打印console.log(this. route属性控制台打印console.log(this.router),可以看出
push是在this.$router的原型上,所以push是VueRouter类的一个实例
理解push是VueRouter类的一个实例
- VueRouter
function VueRouter() {
}
- 原型对象的方法
VueRouter.prototype.push = function() {
// 函数的上下文为VueRouter类的一个实例
}
let $router = new VueRouter()
$router.push(xxx)
this.$router.push()
所以我们要重写VueRouter.prototype.push的方法
重写push和replace方法–代码
在router/index.js里console.log(VueRouter.prototype)
- router/index.js
思路:使用原本的push|replace方法,传原本的参数this实例,和location, 判断是否有传状态参数,有传;没有传。
// 先把VueRouter原型对象的push,先保存一份
let originPush = VueRouter.prototype.push
let originReplace = VueRouter.prototype.replace
// 重写push|replace
// 第一个参数:告诉原来push方法,你往哪里跳转(传递哪些参数)
VueRouter.prototype.push = function(location, resolve, reject) {
if(resolve && reject) {
// call || appply 区别
// 相同点, 都可以调用函数一次,都可以篡改函数的上下文一次
// 不同点: call与apply传递参数:call传递参数用逗号隔开,apply方法执行,传递数组
originPush.call(this, location, resolve, reject)
} else {
originPush.call(this, location, () => {}, () => {} )
}
}
VueRouter.prototype.replace = function(location, resolve, reject) {
if(resolve && reject) {
originReplace.call(this, location, resolve, reject)
} else {
originReplace.call(this, location, () => {}, () => {} )
}
}