一、前言
在上一章的学习中,通过举例说明,我们了解了VueRouter中命名路由、命名视图的使用方法,以及如何通过query查询参数传参,或者是采用param传参的方式实现路由间的参数传递。通过学习我们可以发现,在实现路由间的参数传递时,我们将VueRouter与我们的组件强耦合在一起,这无疑是不合适的,那么本章我们就来学习,如何实现组件和VueRouter之间的解耦。
学习系列目录地址:https://www.cnblogs.com/danvic712/p/9549100.html
仓储地址:https://github.com/Lanesra712/VueTrial/blob/master/chapter02-bronze/router/decoupling.html
二、干货合集
1、编程式导航
在使用VueRouter的时候,我们通常会通过router-link标签去生成跳转到指定路由的链接,但是在实际的前端开发中,我们更多的是通过js的方式进行跳转。就像我们很常见的一个交互需求,用户提交表单,提交成功后跳转到上一页面,提交失败则留在当前页。这时候如果我们还是通过router-link标签进行跳转就不合适了,我们需要通过js根据表单返回的状态进行动态的判断。
在使用VueRouter时,我们已经将VueRouter的实例挂载到了Vue实例上,因此我们就可以借助$router的实例方法,通过编写js代码的方式实现路由间的跳转,而这种方式就是一种编程式的路由导航。
在VueRouter中具有三种导航方法,分别为push、replace和go。我们最常见的通过在页面上设置router-link标签进行路由地址间的跳转,就等同于执行了一次push方法。
在这一小节的示例中,我将使用编程式导航实现通过点击不同的按钮实现路由间的跳转,最终实现的示意图如下所示。
在之前学习VueRouter的基础使用方法时,我们了解到,前端路由的实现方式,实际上就是对于浏览器的historyapi的操作。浏览器的history对象提供了对浏览器的会话历史的访问,它暴露了很多有用的方法和属性,允许我们在用户浏览历史中向前和向后跳转,同时从HTML5开始提供了对history栈中内容的操作。
而VueRouter所提供的push、replace和go方法则完全可以对应到浏览器historyapi中所提供的history.pushState、history.replaceState和history.go方法。
1.1、push
当我们需要跳转新页面时,我们就可以通过push方法将一条新的路由记录添加到浏览器的history栈中,通过history的自身特性,从而驱使浏览器进行页面的跳转。同时,因为在history会话历史中会一直保留着这个路由信息,所以当我们后退时还是可以退回到当前的页面。
在push方法中,参数可以是一个字符串路径,或者是一个描述地址的对象,这里其实就等同于我们调用了history.pushState方法。
//字符串=>/first
this.$router.push('first')
//对象=>/first
this.$router.push({path:'first'})
//带查询参数=>/first?abc=123
this.$router.push({path:'first',query:{abc:'123'}})
这里需要注意,当我们传递的参数为一个对象并且当path与params共同使用时,对象中的params属性不会起任何的作用,我们需要采用命名路由的方式进行跳转,或者是直接使用带有参数的全路径。
constuserId='123'
//使用命名路由=>/user/123
this.$router.push({name:'user',params:{userId}})
//使用带有参数的全路径=>/user/123
this.$router.push({path:`/user/${userId}`})
//这里的params不生效=>/user
this.$router.push({path:'/user',params:{userId}})
1.2、go
当我们使用go方法时,我们就可以在history记录中向前或者后退多少步,也就是说通过go方法你可以在已经存储的history路由历史中来回跳。
//在浏览器记录中前进一步,等同于history.forward()
this.$router.go(1)
//后退一步记录,等同于history.back()
this.$router.go(-1)
//前进3步记录
this.$router.go(3)
//如果history记录不够用,那就默默地失败呗
this.$router.go(-100)
this.$router.go(100)
1.3、replace
replace方法同样可以达到实现路由跳转的目的,不过,从名字中你也可以看出,与使用push方法跳转不同是,当我们使用replace方法时,并不会往history栈中新增一条新的记录,而是会替换掉当前的记录,因此,你无法通过后退按钮再回到被替换前的页面。
this.$router.replace({
path:'/special'
})
通过编程式路由实现路由间切换的示例代码如下所示,你可以自己尝试一下,去熟悉如何通过js来实现路由地址间的切换。
<divid="app">
<divclass="main">
<divclass="btn-toolbar"role="toolbar"aria-label="Toolbarwithbuttongroups">
<divclass="btn-groupmr-2"role="group"aria-label="Firstgroup">
<buttontype="button"class="btnbtn-secondary"@click="goFirst">第一页</button>
<buttontype="button"class="btnbtn-secondary"@click="goSecond">第二页</button>
<buttontype="button"class="btnbtn-secondary"@click="goThird">第三页</button>
<buttontype="button"class="btnbtn-secondary"@click="goFourth">第四页</button>
</div>
<divclass="btn-groupmr-2"role="group"aria-label="Secondgroup">
<buttontype="button"class="btnbtn-secondary"@click="pre">后退</button>
<buttontype="button"class="btnbtn-secondary"@click="next">前进</button>
</div>
<divclass="btn-groupmr-2"role="group"aria-label="Thirdgroup">
<buttontype="button"class="btnbtn-secondary"@click="replace">替换当前页为特殊页</button>
</div>
</div>
<router-view></router-view>
</div>
</div>
<script>
constfirst={
template:'<h3>当前是第一页</h3>'
}
constsecond={
template:'<h3>当前是第二页</h3>'
}
constthird={
template:'<h3>当前是第三页</h3>'
}
constfourth={
template:'<h3>当前是第四页</h3>'
}
constspecial={
template:'<h3>特殊页面</h3>'
}
constrouter=newVueRouter({
routes:[{
path:'/first',
component:first
},{
path:'/second',
component:second
},{
path:'/third',
component:third
},{
path:'/fourth',
component:fourth
},{
path:'/special',
component:special
}]
})
constvm=newVue({
el:'#app',
data:{},
methods:{
goFirst(){
this.$router.push({
path:'/first'
})
},
goSecond(){
this.$router.push({
path:'/second'
})
},
goThird(){
this.$router.push({
path:'/third'
})
},
goFourth(){
this.$router.push({
path:'/fourth'
})
},
next(){
this.$router.go(1)
},
pre(){
this.$router.go(-1)
},
replace(){
this.$router.replace({
path:'/special'
})
}
},
router:router
})
</script>
2、解耦
在文章开头我们有提到过,在使用路由传参的时候,我们将组件与VueRouter强绑定在了一块,这意味着在任何需要获取路由参数的地方,我们都需要加载VueRouter。那么,如何解决这一强绑定呢?
在之前学习组件相关的知识时,我们提到了可以通过组件的props选项来实现子组件接收父组件传递的值。而在VueRouter中,同样给我们提供了通过使用组件的props选项来进行解耦的功能。
在下面的示例中,在定义路由模板时,我们通过指定需要传递的参数为props选项中的一个数据项,之后,我们通过在定义路由规则时,指定props属性为true,即可实现对于组件以及VueRouter之间的解耦。
<script>
constsecond={
props:['id'],
template:'<h3>当前是第二页---{{id}}</h3>'
}
constrouter=newVueRouter({
routes:[{
path:'/second/:id',
component:second,
props:true
}]
})
constvm=newVue({
el:'#app',
data:{},
methods:{
goSecond(){
this.$router.push({
path:'/second'
})
}
},
router:router
})
</script>
可以看到,这里采用param传参的方式进行参数传递,而在组件中我们并没有加载VueRouter实例,也完成了对于路由参数的获取。需要注意的是,采用此方法,只能实现基于param方式进行传参的解耦。
针对定义路由规则时,指定props属性为true这一种情况,在VueRouter中,我们还可以给路由规则的props属性定义成一个对象或是函数。不过,如果定义成对象或是函数,此时并不能实现对于组件以及VueRouter间的解耦。
在将路由规则的props定义成对象后,此时不管路由参数中传递是任何值,最终获取到的都是对象中的值。同时,需要注意的是,props中的属性值必须是静态的,也就是说,你不能采用类似于子组件同步获取父组件传递的值作为props中的属性值。
<script>
constthird={
props:['name'],
template:'<h3>当前是第三页---{{name}}</h3>'
}
constrouter=newVueRouter({
routes:[{
path:'/third/:name',
component:third,
props:{
name:'zhangsan'
}
}]
})
constvm=newVue({
el:'#app',
data:{},
methods:{
goThird(){
this.$router.push({
path:'/third'
})
}
},
router:router
})
</script>
在对象模式中,我们只能接收静态的props属性值,而当我们使用函数模式之后,就可以对静态值做数据的进一步加工或者是与路由传参的值进行结合。
<script>
constfourth={
props:['id','name'],
template:'<h3>当前是第四页---{{id}}---{{name}}</h3>'
}
constrouter=newVueRouter({
routes:[{
path:'/fourth',
component:fourth,
props:(route)=>({
id:route.query.id,
name:'zhangsan'
})
}]
})
constvm=newVue({
el:'#app',
data:{},
methods:{
goFourth(){
this.$router.push({
path:'/fourth'
})
}
},
router:router
})
</script>
三、总结
这一章主要学习了如何通过使用VueRouter的实例方法,从而实现编程式导航,以及如何实现组件与VueRouter之间的解耦。至此,VueRouter的一些基础使用方法也就大概介绍完了,其它的知识点将在后面的项目中具体使用到的时候再进行介绍,欢迎持续关注哈~~~
四、参考
1、HistoryAPI与浏览器历史堆栈管理
2、可能比文档还详细--VueRouter完全指北
3、十全大补vue-router
如需转载,请注明文章出处和来源网址:http://www.divcss5.com/html/h56548.shtml