字节一面:你来讲讲Vue路由组件间通信方式

我们在开发单页面应用时,经常需要进入某个路由后使用传递过来的参数从服务器获取数据,那么我们是怎样实现路由组件间通信的呢,这里我给大家总结出了四种路由组件间常用的通信方式。

一、基本知识

想要掌握路由传参,首先我们得知道跳转路由的2种基本方式,即声明式路由导航和编程式路由导航。

声明式路由导航

直接写在模板(template)中,结构简单使用方便,但是只能放在<router-link>标签中使用,<router-link>标签会将路由转成<a>标签,通过点击跳转路由,因此局限性也非常大。

基本使用:

要想能够跳转,需要将所有的a标签换成<router-link>。

<router-link :to="xxx" ></router-link>

要想让组件在页面中的相应位置显示,要使用<router-view>。

<router-view></router-view>

编程式路由导航:

需要写在js中,结构也不算复杂,优势在于非常灵活,不受固定标签限制,可以在任意情景下转跳路由。

路由对象$router是VueRouter的一个对象,通过Vue.use(VueRouter)和Vue构造函数得到一个router的全局实例对象,他包含了所有的路由,包含了许多关键的对象和属性。

在Vue实例内部,我们可以通过$router访问路由实例。从而就可以调用push方法,等同于点击<router-link>跳转。

 

基本使用:

this.$router.push()

// 字符串

this.$router.push('home')

// 对象

this.$router.push({ path: 'home' })

// 命名的路由

this.$router.push({ name: 'user', params: { userId: '123' }}

replace跟push很像,唯一的不同就是,它不会向history添加新记录,而是直接替换掉当前的history记录。

基本使用:

this.$router.replace()

注意点:

如果使用path跳转的话,必须使用query方式传参,若使用params传参的话params参数会丢失。

声明式路由导航和编程式路由导航的区别

  • 声明式导航是直接渲染到页面的,比如a链接;
  • 编程式导航则是用在js处理逻辑后需要页面跳转,比如点击button按钮跳转。

二、query

query传参类似于网络请求中的 get 请求,query传过去的参数会拼接在地址栏中(?name=xx)。query较为灵活既可以配合path使用,也能配合name使用。

声明式

<router-link :to="{ path: '/home', query: { username: username } }">

// 取值

this.$route.query.username

编程式

data:{

username: ''

},

login() {

...

this.$router.push({

path: '/home',

query: { username: this.username },

})

}

三、params

params传参类似于网络请求中的post请求,当使用编程式路由导航使用path跳转时,如果没有在对应的位置添加params参数,params传过去的参数就不会显示在地址栏中(并且不能刷新)。

声明式

<router-link :to="{ name: 'home', params: { username: username } }">

// 取值

this.$route.params.username

编程式

data:{

username: ''

},

login() {

...

this.$router.push({

name: 'home', //注意使用 params 时一定不能使用 path

params: { username: this.username },

})

}

注意事项

当使用编程式路由导航时通过params传参后,刷新页面会失去拿到的参数。所以路由参数要修改为 '/login/:username'(官方称为动态路由)。

const routes = [

{

path: '/login',

component: Login

},

{

path: '/home/:username',

name: '/home',

component: Home

}

但是这样就不会类似于 post 请求,他会把接收到的参数替换作为地址。

假如传入参数为:params: { username: ‘admin’},那么最终访问的地址为:http://localhost:8080/home/admin。

query传参和params传参的区别

query可以通过name属性或者path属性来引入路由,而params只能通过name属性来引入路由;在使用params传递时如果指定了path属性而没有name属性,那么界面能成功跳转但是不能接受到传递过来的参数;

query传递参数时会地址栏会发生改变,传递参数会携带在路径中,而params则不会;

编程式导航使用path跳转时,在刷新界面后,query传递的参数不会丢失,而params会丢失。

四、props

我们可以通过配置路由时的props属性,将params/query携带的参数,在组件中用props属性来接收,这样用时可以直接使用,就不需要$route.params.xxx/$route.query.xxx的形式了。

路由规则配置中,props参数的使用有如下三种方式:

  • props值是一个对象。
  • props值是一个布尔值。
  • props值是一个函数。

配置方法

{

name: "detail",

path: "/detail",

component: Detail,

/**

方式一,值为对象,对象中的key-value会以props的形式传递给Detail组件,

但是传递的值都是一样的,不推荐

props: {

id: '123',

title: '消息001',

},

**/

/**

方式二,值为布尔值,若布尔值为真,就会把该组件收到的所有params参数,以props的形式传式传递给Detail组件, 但之这种方式只适用于params参数

props: true,

**/

/**

方式三,值为函数,内置传参$route,可以使用结构赋值形式

**/

props({ query }) {

return { id: query.id, title: query.title };

},

}

五、meta

我们经常会在进入一个页面时判断是否已经登陆,经常会用到路由导航守卫router.beforeEach(to, from, next), 一个两个页面还好,但是多的话,就会麻烦,并且路由还会嵌套。这时可以使用meta。

在配置路由时,我们可以给每个路由添加一个自定义的meta对象,在meta对象中可以设置一些状态,来进行一些操作。项目中经常用它来做登录校验。

const router = new VueRouter({

routes: [

{

path: "/detail",

component: Detail,

meta: { requiresAuth: true }, //meta参数可以是一个对象,也可以是一个数组,配置每个路由的一些信息,类似于每个路由的标识符

},

],

});

// 取值

this.$route.meta

六、实战bug解析

面试场景:编程式路由跳转到当前路由, 参数不变, 会报出错误?

说明情况:

之前的项目这种操作没有这个问题,后面的一个项目(2019.8之后)开始有这个问题, 而且是声明式跳转没有, 只有编程式跳转有。当编程式跳转到当前路由且参数数据不变, 就会出警告错误:错误: Avoided redundant navigation to current location(重复跳转当前路由)。

原因: vue-router在3.1.0版本(2019.8)引入了push()的promise的语法, 如果没有通过参数指定回调 函数就返回一个promise来指定成功/失败的回调, 且内部会判断如果要跳转的路径和参数 都没有变化, 会抛出一个失败的promise。

说明文档: https://github.com/vuejs/vue-router/releases?after=v3.3.1

解决:

办法1: 在每次push时指定回调函数或catch错误。

push('/xxx', () => {}) // 声明式路由跳转本质就是这样执行的。

push('/xxx').catch(() => {})

办法2: 重写VueRouter原型上的push方法 (比较好)。

如果没有指定回调函数, 需要调用原本的push()后catch()来处理错误的 promise。

如果传入了回调函数, 本身就没问题, 直接调用原本的push()就可以。

const originPush = VueRouter.prototype.push;

VueRouter.prototype.push = function (

location,

onComplete,

onAbort

) {

console.log("push()", onComplete, onAbort);

// 判断如果没有指定回调函数, 通过call调用源函数并使用catch来处理错误

if (onComplete === undefined && onAbort === undefined) {

// 使用的新语法

return originPush.call(this, location).catch(() => {});

} else {

// 如果有指定任意回调函数, 通过call调用源push函数处理

return originPush.call(this, location, onComplete, onAbort);

}

};

说明:声明式路由跳转之所有没有问题, 是因为默认传入了成功的空回调函数。

query和params分别都有三种形式可以传参:

  • router-link形式。
  • 通过path匹配路由的编程式导航形式。
  • 通过name匹配路由的编程式导航形式。

而这其中只有params通过name匹配路由的编程式导航形式不会在路径中带有参数(且刷新页面参数不会丢失),其他都会带有参数值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值