一、问题解析
今天在使用 Vue命名视图发现了两个问题,首先看下代码
路由部分代码
{
path: Prefix('/device/:id'),
name: 'Device',
components: {tabbar: Device},
meta: {
title: '',
},
props: true,
},
{
path: Prefix('/stop/:deviceId/:goodsId'),
name: 'Stop',
component: Stop,
meta: {
title: '',
},
props: true,
},
这段代码包含两个路由,Device
和Stop
- 首先当进入
Device
时无法到props
中的id,这时需要修改成如下方式
props: {
tabbar: true,
},
官方解释是 对于包含命名视图的路由,你必须分别为每个命名视图添加 props
选项
- 第二个问题是当从路由
Device
的组件跳转到Stop
路由的组件的时候,不能正确跳转
当把1的问题解决好以后,2的问题也解决好了,至于原理,应该是vue-router内部的实现机制,具体的原理还不清楚。
二、命名视图的简单用法
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: Foo,
a: Bar,
b: Baz
}
}
]
})
这样就可以正常使用了,如果有布局的需求,就要自己进行布局。
三、我什么会引入命名视图
<template v-if="showTabBar">
<div class="p-app-body">
<router-view name="tabbar"></router-view>
</div>
<div class="p-app-tabbar">
<tab-bar v-model="routerName"></tab-bar>
</div>
</template>
<template v-if="hideTabBar">
<router-view></router-view>
</template>
上面这段代码是我现在可以正常运行的代码
我部分页面是有tabBar
的,这时候就需要用到全屏,没有用到tabBar
的页面正常显示就好。
有问题的代码
<template v-if="showTabBar">
<div class="p-app-body">
<router-view></router-view>
</div>
<div class="p-app-tabbar">
<tab-bar v-model="routerName"></tab-bar>
</div>
</template>
<template v-else>
<router-view></router-view>
</template>
问题主要是当我路由切换的时候可能导致我的组件加载两次,何为两次呢。
有一个Me
路由(需要显示tabBar
)和一个Order
路由(不需要显示tabBar
)时,当有Me
跳转至Order
时,showTabBar
会由true
变为false
,因为异步的原因,值改变的时候vue
路由还没有切换,因为都是路由的默认组件,所以Me
路由对应的组件还会要再加载一次,再马上切换到Order
路由,正常情况下是没有感官上的感受的,如果Me
组件在created阶段删除掉了Order
组件需要用的的Cookie
、localStorage
、sessionStorage
等,将导致页面不能正确显示,所以才会引入最上面说到的问题,同时还会引起下面这个问题。
说一下为什么要用两个v-if
而不是使用v-if
和v-else
。
假设我们使用v-if
和v-else
,当首次加载的时候页面已经加载完毕,但是路由还没有完全加载,页面就会使用v-else进行加载(或者因为异步的原因路由已经加载完毕,但是我showTabBar
是false),当路由加载完成以后发现showTabBar
是true
,这时就需要使用v-if
加载,导致路由对应的组件加载两次,解决的方法就是增加一个v-if
,而且每个都要有去空判断。
showTabBar() {
return this.routerName && listTabBar.indexOf(this.routerName) >= 0
},
hideTabBar() {
return this.routerName && listTabBar.indexOf(this.routerName) < 0
},
增加这一段之后因为有了去空解决了首次重复加载问题,那是否可以解决我最开始的问题(切换路由组件加载两次)呢。
当然是否定的。还是回到了出现这个问题的原因,因为异步导致v-if切换和路由切换不是同步的,所有是不可以的。
总结
如果Vue
根节点是要根据v-if
显示不同的内容并且每个内容快都包含路由视图时就需要考虑两个方面
1、是否能容忍组件加载两次,不能的话就要使用命名视图。
2、是否能容忍首次重复加载,不能的话就要给每个单独写v-if并去掉空。
异议
其实解决这个问题也可以根据路由进行区分,再加一个上级路由,需要用到tabBar
的就统一有一个上级路由,把tabBar
和全屏都写在这个上级路由里面。