vue 内置组件 <Transition> 的实践经历

记录最近发生的一个事情。

一位开发者在使用 vue3-vant-mobile 向上构建自己业务的时候,使用了 vue 的内置组件 transition 来实现组件级路由过渡,这样当页面进入的时候,有一个向右的偏移量,退出返回的时候,有一个向左的偏移量,大白话讲就是让人看着有一个进入进出的感觉。

补充一点,vue3-vant-mobile 是一个专注于 Vue 生态系统的移动 web 应用模板,帮助你快速完成业务开发。由于模版本身没有这个功能,所以是开发者自己的实现,后边作为新的特性,被补充到模版里面去了。

不过,在他实现的过程中,发现了一个不可忽略的问题,路由过渡的中间会出现短暂的白屏,下面是他发给我的一个demo,效果如下所示。

很明显看到一个白屏。刚开始我以为是动画延迟时间导致的,比如下面这段代码。

xml 复制代码
<!-- App.vue -->
<template>
  <VanConfigProvider :theme="theme">
    <router-view v-slot="{ Component, route }">
      <transition :name="useRouteTransitionNameHook().routeTransitionName">
        <div :key="route.name" class="app-wrapper">
          <component :is="Component" />
        </div>
      </transition>
    </router-view>
  </VanConfigProvider>
</template>

<style lang="less" scoped>
.slide-left-enter-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-right-leave-active {
  transition: all 0.5s;
}
.slide-left-enter-from,
.slide-right-leave-to {
  transform: translateX(100%);
}
.slide-left-leave-to,
.slide-right-enter-from {
  transform: translateX(-100%);
}
</style>

我让他把时间设置的短一点,但是这样做只是会让动画非常快,还是会存在白屏。他告诉我说,在其他项目上即便 0.5s ,也是非常丝滑的。我一度怀疑是我的模版代码影响到了过渡动画。所以,我开始在 vue3-vant-mobile 进行实验。我先是使用逐步过滤的办法,删掉一个个插件,然后看效果,结果就是插件都快卸载没有了,这个过渡动画还是存在白屏。而且我还发现了一个新的问题,就是布局有点乱,从一级页面跳往二级页面的过程中,二级页面是从下往上出来的。

一开始,我没有太关注这个布局问题,只是想着先把白屏的问题解决掉,其实这是发现问题的一个线索。

我还是不甘心,使用 vite 模版起了一个新项目,结果如下。

可以看到白屏的问题依然存在。我开始要相信这就是动画时间所导致的白屏效果。到这个阶段我已经花了好几个小时了,我开始想要放弃,并认为这是 vue 本身的问题。

事情了隔了一天,这个事情还是牵着我的心,我打算再看看那个demo,这个时候我开始注意动画过渡的过程中出现了一个长长的滚动条,因为我们知道浏览器滚动条的出现意味着内容超过了元素本身的高度,就会出现滚动条对吧? 对!我的二级页面可是正好的一个视高,怎么会出现滚动条呢?一个前端开发者的职业本能的想要看一下dom 是什么样的。

大家仔细看右侧的 dom 结构,同时出现了两个 div , 这两个 div 块分别代表着两个页面。 我继续跟着这个线索往下发现问题,我要让那个出现滚动条原因浮出水面。

当我切换页面的时候,我快速下滑至浏览器底部,这个时候另外一个页面也被渲染出来了。原来,当我动画过渡的时候,一个视口范围内同时出现了两个页面,这就是导致出现滚动条的原因。而且这也是为什么二级页面是从下往上出现的原因;同样的,为什么会有一段时间的白屏,因为布局渲染出现了错乱。仔细看他发给我的 demo,因为过渡动画的缘故,也会有两个 div 块同时出现在 dom 树内,也存在滚动条。

到这里,其实我才定位到真正的问题,也只有把问题定位清楚了,才能真正解决这个问题。我开始利用 css 的绝对定位去解决布局的问题。

arduino 复制代码
// app.less
#app {
  min-height: 100vh;
  position: relative;
  overflow-x: hidden;
}
xml 复制代码
// App.vue
<style scoped>
.app-wrapper {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow-y: auto;
}
</style>

在app应用的全局上利用相对定位,然后在每个页面的父元素上使用绝对定位是一个解决办法,不过这种方法我那时还不知道是不是最优的方案,我担心有风险,因为毕竟它是脱离文档流渲染的,而且这种布局也会有性能问题。而且,还有一个隐性的问题,就是把其它元素设置为绝对定位以后,你还要考虑重叠的问题,所以设置一个合适的 z-index 数值也是一个要考虑的事情。不过好在,前面的性能问题不用太在意,毕竟现代浏览器渲染性能还是很高的,最后一个问题呢,因为是给路由级别的组件增加的绝对定位,所以组件内元素有绝对定位,按照重叠排序规则,就应该显示在最上面。最后的效果如下,确实丝滑了很多。

后来,我把这个组件过渡动画特性也加到了 vue3-vant-mobile 上面,这样更多人可以使用了。我也特别感谢那位开发者不辞辛苦的提出这个问题,而且部分代码也参考了他的实现,谢谢他。

事情还没有结束,又过了一天,我在为我的过渡动画方案寻找最佳实践的时候,我去看了 vue 内置组件 transition 的官网文档,发现这种绝对定位的方案,官网早就侧面的说过。我很后悔当初我在找解决问题方法的时候,没有仔细看官网文档。下面是官网关于过渡模式的截图。

里面不仅提到了针对这种布局的解决方法,而且还提到了动态组件的过渡模式,可以使用 mode=out-in。这种模式会等待离开动画结束后,再执行进入的动画,这样一个视口就不会出现两个页面的问题,布局错误的问题也就解决了。似乎是一种动态组件过渡的最佳方案。其实,这种方案会有所谓"白屏"的问题,我不确定这种说法对不对,只是当下没有合适的叫法。也许对很多人来说,这种问题也可以忽略。增加了这种模式的组件,效果如下。

其实,官网的例子也有这个问题。

所以,其实选择哪种方案,还要取决于你的项目的使用情景和需求来的。

最后,如果你有其它更好的方案或者意见,请在评论区留言。

相关推荐
m0_748247551 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
m0_748255022 小时前
前端常用算法集合
前端·算法
真的很上进2 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203982 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2343 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若1233 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~4 小时前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语4 小时前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
supermapsupport4 小时前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
brrdg_sefg4 小时前
WEB 漏洞 - 文件包含漏洞深度解析
前端·网络·安全