【笔记】VueRouter 路由过度效果 - 左出右进
主要是用于一种场景,用于解决切换路由时出现滚动条,或者渲染抖动的情况。:
- 前进时(/ -> /docs),左出-右进
- 后退时(/docs -> /),右出-左进
演示如下:
实现时会用到如下组件:
- <Transition name="classname"> 文档:内置组件 | Transition
以及需要路由守卫和路由视图插槽的参与:
- router.afterEach(to => to.meta)
- <RouterView v-slot="{ Component, route }">
正常的路由列表配置就不过多描述。
1. 页面元素构成
首先,我们需要确定路由的组成结构,这里以常见结构为例:
<RouterView v-slot="{ Component, route }">
<Transition :name="route.meta.transitionName">
<component :is="Component" />
</Transition>
</RouterView>
- 使用路由插槽属性将路由切换的组件获取出来。
- 一个组件就是一个页面,Transition 即可满足需求,所以这里不需要
TransitionGroup。 - 因为要区分前进后退或者是需要区分状态,这里都会用到 route.meta 自定义属性,这里定义了一个 transitionName 的属性,来定义过度的样式。
- 使用component来接受插槽传递出来的组件进行渲染。
2. 利用导航守卫控制过度样式
如果只想拥有动画不必区分跳转情况的,则可不考虑。
这里是需要区分左右,且动画表现一致,即离开的页面从左侧出去,跳转的页面从右侧进入。
那么就会需要路由导航的介入了。
router.afterEach((to, from) => {
// 记录进入的路由 url
const toDepth = to.path === '/' ? 0 : to.path.split('/').length
// 记录离开的路由 url
const fromDepth = from.path === '/' ? 0 : from.path.split('/').length
// 切换过度样式
to.meta.transitionName = toDepth < fromDepth ? 'fade-left' : 'fade-right'
// 控制首页载入时候不启用路由过度动画
if (from.fullPath === '/' && !from.name) {
to.meta.transitionName = ''
}
})
- 使用 (top, from) 来获取 path 信息,切分 / 来获取 url 深度
- 当 to < from 的深度时,则使用左侧退出过度,反之是右侧退出过度
- 当然还需要处理首次进入时的状态,这里较为简单,如果有特殊的首页逻辑,那么针对性处理即可
3. 过度样式
进入状态
- v-enter-from:进入动画的起始状态。在元素插入之前添加,在元素插入完成后的下一帧移除。
- v-enter-active:进入动画的生效状态。应用于整个进入动画阶段。在元素被插入之前添加,在过渡或动画完成之后移除。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型。
- v-enter-to:进入动画的结束状态。在元素插入完成后的下一帧被添加 (也就是 v-enter-from 被移除的同时),在过渡或动画完成之后移除。
离开状态
- v-leave-from:离开动画的起始状态。在离开过渡效果被触发时立即添加,在一帧后被移除。
- v-leave-active:离开动画的生效状态。应用于整个离开动画阶段。在离开过渡效果被触发时立即添加,在过渡或动画完成之后移除。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。
- v-leave-to:离开动画的结束状态。在一个离开动画被触发后的下一帧被添加 (也就是 v-leave-from 被移除的同时),在过渡或动画完成之后移除。
由于需要控制进出跳转的状态,那么在这就把所有状态都用上了。
/* 路由过度样式 */
/* (1.) */
.fade-left-enter-active,
.fade-left-leave-active,
.fade-right-enter-active,
.fade-right-leave-active {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
height: max-content;
backface-visibility: hidden;
will-change: transform;
transition: transform 0.5s ease, opacity 0.5s ease;
overflow: hidden;
}
/* (2.) */
.fade-left-enter-active,
.fade-right-enter-active {
transition-delay: 0.3s, 0.3s;
}
/* (3.) */
.fade-left-enter-to,
.fade-right-enter-to {
transform: translate3d(0, 0, 0);
}
/* (4.) */
.fade-left-enter-from {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
.fade-right-enter-from {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
/* (5.) */
.fade-left-leave-to {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
.fade-right-leave-to {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
/* (6.) */
.t-start {
min-height: 100vh;
overflow: hidden;
}
- *-enter-active,*-leave-active 激活状态使用 absolute 是为了让组件不影响 body 的结构,从而不会产生滚动条,渲染抖动等。
- *-enter-active 覆盖延迟时间是为了让体感上有个比较明显的进出变化,当然不覆盖延迟也可以,主要看需求和选择。
- *-enter-to 不管左进还是右进,结束时状态一定是表示最终状态,这里是为了不影响元素的定位问题,所以选择了使用 translate3d。
- *-enter-from 让元素的起始位进行 x 轴偏移 100% 即一个页面的宽度。
- *-leave-to 让元素的结束位进行 x 轴偏移 100% 即一个页面的宽度。与 4. *-enter-from 偏移向相反即可。
- .t-start 这里定义了一个样式也是为了处理父级产生滚动条,渲染抖动等情况。
4. 解决父级元素产生滚动条,渲染抖动等情况
为了解决这个情况那么会用到以下事件:
- @before-enter 在元素被插入到 DOM 之前被调用,用这个来设置元素的 "enter-from" 状态
- @after-enter 当元素进入过渡完成时被调用
<RouterView v-slot="{ Component, route }">
<Transition :name="route.meta.transitionName" @before-enter="onBeforeEnter" @after-enter="onAfterEnter">
<component :is="Component" />
</Transition>
</RouterView>
const onBeforeEnter = () => {
document.querySelector('#app')?.classList.toggle('t-start', true)
}
const onAfterEnter = () => {
document.querySelector('#app')?.classList.toggle('t-start', false)
}
用到这个主要的情况是在执行过度动画中,由于切换不同周期的 Transition-class 导致的。
那么需要在 Transition 上新增 @before-enter、@after-enter 事件,为父级添加一个 高度、隐藏滚动条 的样式即可解决。
这个问题在不同布局样式中不一定会出现,主要还是取决于如何定义布局样式的行为。 以 html>body>#app 布局结构在如下定义时不会出现此问题。
html,
body,
#app {
width: 100%;
height: 100%;
overflow: hidden;
}
版权声明: 本文版权属于作者 林小帅,未经授权不得转载及二次修改。 转载或合作请在下方留言及联系方式。
转载自:https://juejin.cn/post/7220335452711125053