返回页面动画错乱的问题。
来源:16-8 通用组件:虚拟任务栈处理

城北丶
2023-07-12
点击我的页面返回按钮时首页的动画并没有添加back动画,而依然是push动画。即使把老师的transition-router-view组件代码全部复制到项目中也会有这个问题。所以我想问下老师这个问题该如何解决?如果不加keep-alive的话,动画是正常的。
代码如下:
<template>
<!--
这个组件用于页面切换时的过渡动画
router-view 是路由的出口,用于渲染路由的内容,v-slot="{ Component }"是插槽语法,用于获取当前路由组件
transition 是Vue内置的过渡组件,name属性用于指定过渡动画的名称
keep-alive 是Vue内置的缓存组件,用于缓存组件,避免组件被销毁
component 是Vue内置的动态组件,用于渲染组件
-->
<router-view v-slot="{ Component }">
<!--
@before-enter="beforeEnter"是动画的钩子函数,用于在动画开始前执行
@after-leave="afterLeave"是动画的钩子函数,用于在动画结束后执行
-->
<transition
:name="transitionName"
@before-enter="beforeEnter"
@after-leave="afterLeave"
>
<!--
isAnimation:当动画开始执行给当前组件设置样式,这样可以避免两个组件切换的时候被顶下去的问题
includes:匹配需要缓存的组件名称,如果不匹配则不缓存
-->
<keep-alive :include="virtualTaskStack">
<component
:is="Component"
:class="{
'fixed top-0 left-0 bottom-0 w-screen h-screen overflow-hidden z-50':
isAnimation
}"
:key="$route.fullPath"
/>
</keep-alive>
</transition>
</router-view>
</template>
<script>
// 不使用动画
const NONE = 'none'
// 进入动画
const PUSH = 'push'
// 离开动画
const BACK = 'back'
// 路由动画的类型(枚举)
const ROUTER_TYPE_ENUM = [NONE, PUSH, BACK]
</script>
<script setup>
const props = defineProps({
// 路由的跳转动画类型,PUSH 表示进入,BACK 表示离开
routerType: {
type: String,
default: NONE, // 默认不使用动画
validator: (value) => {
const result = ROUTER_TYPE_ENUM.includes(value)
if (!result) {
throw new Error(
`你的 routerType 必须是 ${ROUTER_TYPE_ENUM.join('、')} 中的一个`
)
}
return result
}
},
// 首页的组件名称,用于判断是否是首页
mainComponentName: {
type: String,
required: true
}
})
// 任务栈,存放需要缓存的组件名称,默认只有首页
const virtualTaskStack = ref([props.mainComponentName])
const router = useRouter()
// 跳转动画的名称
const transitionName = ref('')
// 监听路由的前置守卫,每次路由跳转前都会执行
router.beforeEach((to, from) => {
// 设置当前路由的过度动画名称
transitionName.value = props.routerType
// 如果是进入页面,则将页面名称入栈,进行缓存,这样可以让页面之间切换时不会被销毁
if (props.routerType === PUSH) {
// 入栈
virtualTaskStack.value.push(to.name)
} else if (props.routerType === BACK) {
// 出栈
virtualTaskStack.value.pop()
}
// 进入首页默认清空栈
if (to.name === props.mainComponentName) {
clearTask()
}
})
// 当前动画是否执行完毕,false为执行完毕
const isAnimation = ref(false)
// 动画开始前执行的函数
const beforeEnter = () => {
// 动画开始前,将动画状态设置为true,表示动画正在执行
isAnimation.value = true
}
// 动画结束后执行的函数
const afterLeave = () => {
// 动画结束后,将动画状态设置为false,表示动画已经执行完毕
isAnimation.value = false
transitionName.value = ''
}
/**
* 清空栈
*/
const clearTask = () => {
virtualTaskStack.value = [props.mainComponentName]
}
</script>
<style lang="scss" scoped>
// push页面时:新页面的进入动画
.push-enter-active {
animation-name: push-in;
animation-duration: 10s;
}
// push页面时:老页面的退出动画
.push-leave-active {
animation-name: push-out;
animation-duration: 10s;
}
// push页面时:新页面的进入动画
@keyframes push-in {
0% {
transform: translate(100%, 0);
}
100% {
transform: translate(0, 0);
}
}
// push页面时:老页面的退出动画
@keyframes push-out {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(-50%, 0);
}
}
// 后退页面时:即将展示的页面动画
.back-enter-active {
animation-name: back-in;
animation-duration: 10s;
}
// 后退页面时:后退的页面执行的动画
.back-leave-active {
animation-name: back-out;
animation-duration: 10s;
}
// 后退页面时:即将展示的页面动画
@keyframes back-in {
0% {
transform: translate(-100%, 0);
}
100% {
transform: translate(0, 0);
}
}
// 后退页面时:后退的页面执行的动画
@keyframes back-out {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(50%, 0);
}
}
</style>
写回答
1回答
-
Sunday
2023-07-12
你好
transition-router-view 这个组件的话,需要保证内部的组件都有正确的入栈(push)和出栈(pop)行为才可以的。
012023-07-12
相似问题