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

TailwindCSS动画结合v-for时失效问题求助

问题:多弹窗时过渡动画失效

我在屏幕右上角实现了一组可点击关闭的弹窗消息,每个弹窗都配置了slide-fade过渡效果。单个弹窗时动画正常工作,但多个弹窗并存时,过渡效果就失效了,求解决办法。


相关代码

<template>
    <Transition name="slide-fade" @click="close">
        <div class="bg-green-100 opacity-95 rounded-lg py-5 px-6 mb-3 text-green-700 inline-flex items-center text-sm" role="alert">
            <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="check-circle" class="w-8 h-8 mr-2 fill-current" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
                <path fill="currentColor" d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"></path>
            </svg>
            {{ placeholder }}
        </div>
    </Transition>
</template>

<script>
export default {
    name: 'popupComponent',
    methods: {
        close () {
            this.$emit('close', this.arrIndex)
        }
    },
    props: {
        placeholder: String, 
        arrIndex: Number
    }
}
</script>

<style scoped>
.slide-fade-enter-active {
  transition: all 0.3s ease-out;
}

.slide-fade-leave-active {
  transition: all 0.8s cubic-bezier(.25,.59,.63,.92);
}

.slide-fade-enter-from,
.slide-fade-leave-to {
  transform: translateX(20px);
  opacity: 0;
}
</style>

App.vue

<template>
  <div class="absolute z-10 right-0 p-2 max-w-md">
     <div class="flex flex-col gap-y-2 max-h-96 overflow-y-hidden">
        <popup v-for="(content, index) in popup_content.slice().reverse()" :key="index" @close="closePopup" :arrIndex="(popup_status.length-1) - index"  :placeholder="content"/>
     </div>  
  </div>
</template>

<script>
import popupComponent from './components/popup.vue'

export default {
  data() {
    return {
      popup_content: ['Awesome!', 'Nice!'],
    }
  },
  methods: {
    closePopup(index) {
      this.popup_content.splice(index, 1);
    }
  },
  components: {
    'popup': popupComponent
  },
  name: 'App'
}
</script>

解决方案

1. 替换v-for的key值

当前用数组index作为key,当元素被删除时,后续元素的index会发生变化,Vue会复用现有组件而非重新渲染,导致过渡动画失效。需要改用每个弹窗的唯一标识作为key:

修改App.vue的data结构:

data() {
  return {
    popup_content: [
      { id: 1, content: 'Awesome!' },
      { id: 2, content: 'Nice!' }
    ],
  }
}

更新v-for循环:

<popup 
  v-for="(item, index) in popup_content.slice().reverse()" 
  :key="item.id" 
  @close="closePopup" 
  :arrIndex="(popup_content.length-1) - index"  
  :placeholder="item.content"
/>

2. 修正arrIndex的计算错误

原代码中误用了未定义的popup_status.length,应改为popup_content.length,否则会导致删除索引错误。

3. 给弹窗添加条件渲染控制

当前Transition组件没有绑定显示状态,关闭时组件直接被父组件删除,无法触发过渡动画。需要在popup.vue中添加v-if控制显示:

修改popup.vue的template:

<template>
    <Transition name="slide-fade">
        <div 
          v-if="visible"
          class="bg-green-100 opacity-95 rounded-lg py-5 px-6 mb-3 text-green-700 inline-flex items-center text-sm" 
          role="alert"
          @click="close"
        >
            <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="check-circle" class="w-8 h-8 mr-2 fill-current" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
                <path fill="currentColor" d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"></path>
            </svg>
            {{ placeholder }}
        </div>
    </Transition>
</template>

更新popup.vue的script,添加显示状态控制:

export default {
    name: 'popupComponent',
    data() {
      return {
        visible: true
      }
    },
    methods: {
        close () {
            this.visible = false;
            // 等待过渡动画结束后通知父组件删除元素
            setTimeout(() => {
              this.$emit('close', this.arrIndex)
            }, 800); // 对应leave-active的0.8s过渡时长
        }
    },
    props: {
        placeholder: String, 
        arrIndex: Number
    }
}

内容的提问来源于stack exchange,提问作者JoshJohnson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 04:48:16