You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3过渡动画仅滑入生效,滑出及遮罩无动画问题求助

Vue3 菜单过渡动画失效问题排查与修复

问题描述

使用Vue3父子组件实现菜单过渡动画时,点击Toggle按钮菜单可正常滑入,但无法触发滑出动画;同时遮罩层(cartbar-overlay)完全没有过渡效果。

错误原因

  1. 父组件提前销毁子组件:父组件给子组件添加了v-show="cartVisible",当cartVisible变为false时,子组件会被立即隐藏销毁,内部的<transition>还未执行完离开动画就被移除,导致滑出和遮罩过渡失效。
  2. 双重显示控制冲突:子组件内部已经通过v-show="props.visible"配合<transition>控制元素显示,父组件的外部v-show会打断内部过渡流程。

修复代码

修改后的父组件

<template>
  <div>
    <button @click="cartToggle">Toggle</button>
  </div>
  <div>
    <!-- 移除子组件上的v-show,让子组件内部自行控制过渡逻辑 -->
    <Child
      :visible="cartVisible"
      @update:visible="cartToggle"
    />
  </div>
</template>

<script setup>
import { ref } from "vue";
import Child from "./Child.vue";

const cartVisible = ref(false);
const cartToggle = () => {
  cartVisible.value = !cartVisible.value;
};
</script>

<style scoped>
span {
  cursor: pointer;
}
</style>

修改后的子组件

<script setup lang="ts">
import { toRefs, watchEffect, onBeforeUnmount } from "vue";

const props = defineProps({
  visible: {
    type: Boolean,
    required: true,
    default: false,
  },
});

const { visible } = toRefs(props);

const emit = defineEmits(["update:visible"]);

const hideCartBar = () => {
  emit("update:visible", false);
};

watchEffect(() => {
  document.body.style.overflow = visible.value ? "hidden" : "auto";
  document.body.style.paddingRight = visible.value ? "15px" : "0px";
});

onBeforeUnmount(() => {
  document.body.style.overflow = "auto";
  document.body.style.paddingRight = "0px";
});
</script>

<template>
  <div class="cartbar">
    <!-- 外层容器通过v-show控制,确保过渡完成后再隐藏整体 -->
    <div class="cartbar-wrapper" v-show="visible">
      <transition name="fade">
        <div
          v-show="visible"
          class="cartbar-overlay"
          @click="hideCartBar"
        ></div>
      </transition>
      <transition name="slide">
        <div v-show="visible" class="cartbar-container">
          <div class="cartbar__header">
            <h2>Menu</h2>
            <span @click="hideCartBar" class="cursor-pointer">Close</span>
          </div>
        </div>
      </transition>
    </div>
  </div>
</template>

<style scoped>
/* 过渡动画样式 */
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

.fade-enter-to,
.fade-leave-from {
  opacity: 1;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 500ms;
}

.slide-enter-from,
.slide-leave-to {
  transform: translateX(100%);
}

.slide-enter-to,
.slide-leave-from {
  transform: translateX(0);
}

.slide-enter-active,
.slide-leave-active {
  transition: transform 500ms;
}

/* 菜单容器样式 */
.cursor-pointer {
  cursor: pointer;
}
.cartbar-wrapper {
  z-index: 1300;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  width: 100%;
  padding-left: calc(4px * 9);
}

.cartbar-overlay {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.7);
  opacity: 1;
  cursor: pointer;
}
.cartbar-container {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 460px;
  height: 100%;
  overflow: hidden;
  margin-left: auto;
  padding: calc(4px * 7);
  background-color: #f4f2f1;
  color: #706b5f;
}
</style>

修复说明

  • 父组件移除子组件上的v-show,避免提前销毁子组件中断过渡流程。
  • 子组件的cartbar-wrapper通过v-show="visible"控制整体显示,确保内部<transition>能完整执行进入和离开动画后,再隐藏整个容器。
  • 保留子组件内部过渡元素的v-show="visible",配合<transition>实现遮罩淡入淡出、菜单滑入滑出的完整动画效果。

内容的提问来源于stack exchange,提问作者Mr.P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 18:19:55