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

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

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

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

相关推荐
bysking36 分钟前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓1 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4111 小时前
无网络安装ionic和运行
前端·npm
理想不理想v1 小时前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云1 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
微信:137971205871 小时前
web端手机录音
前端
齐 飞1 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
神仙别闹2 小时前
基于tensorflow和flask的本地图片库web图片搜索引擎
前端·flask·tensorflow
GIS程序媛—椰子2 小时前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_0012 小时前
前端八股文(一)HTML 持续更新中。。。
前端·html