如何为Headless UI Vue Tabs添加过渡动画?
为Headless UI Vue Tabs添加过渡动画的正确方式
你的写法无效的核心原因是:未选中的TabPanel会被自动添加hidden属性(对应CSS的display: none),这会阻断内部TransitionRoot的动画渲染——父元素不可见时,内部元素的过渡动画不会被浏览器执行。
下面是两种可行的解决方案:
方案一:利用TabPanel的卸载机制实现动画
通过给TabGroup添加unmount="true"属性,让未选中的TabPanel完全从DOM中卸载,这样TransitionRoot会在组件挂载/卸载时触发过渡动画:
<template> <TabGroup unmount="true"> <TabList class="flex space-x-1 bg-gray-100 p-1 rounded-md"> <Tab class="px-3 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500">Tab 1</Tab> <Tab class="px-3 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500">Tab 2</Tab> <Tab class="px-3 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500">Tab 3</Tab> </TabList> <TabPanels class="mt-2"> <TabPanel v-for="p in panels" :key="p.id"> <TransitionRoot enter="transition duration-300 ease-out" enter-from="opacity-0 translate-y-4" enter-to="opacity-100 translate-y-0" leave="transition duration-200 ease-in" leave-from="opacity-100 translate-y-0" leave-to="opacity-0 translate-y-4" > <div class="p-4 bg-white rounded-md shadow-sm"> {{ p.content }} </div> </TransitionRoot> </TabPanel> </TabPanels> </TabGroup> </template> <script setup> import { TabGroup, TabList, Tab, TabPanels, TabPanel, TransitionRoot } from '@headlessui/vue' const panels = [ { id: 1, content: 'Tab 1 内容区域' }, { id: 2, content: 'Tab 2 内容区域' }, { id: 3, content: 'Tab 3 内容区域' }, ] </script>
方案二:保留TabPanel在DOM中,手动控制显示状态
如果你希望所有TabPanel始终保留在DOM中,可以覆盖TabPanel的默认隐藏样式,用TransitionRoot的show属性控制内容的显示隐藏:
<template> <TabGroup> <TabList class="flex space-x-1 bg-gray-100 p-1 rounded-md"> <Tab class="px-3 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500">Tab 1</Tab> <Tab class="px-3 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500">Tab 2</Tab> <Tab class="px-3 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-gray-500">Tab 3</Tab> </TabList> <TabPanels class="mt-2"> <TabPanel v-slot="{ selected }" v-for="p in panels" :key="p.id"> <!-- 覆盖默认hidden样式,让TabPanel始终占据空间 --> <div :class="selected ? '' : 'invisible h-0 overflow-hidden'"> <TransitionRoot :show="selected" enter="transition-all duration-300 ease-out" enter-from="opacity-0 transform translate-y-4" enter-to="opacity-100 transform translate-y-0" leave="transition-all duration-200 ease-in" leave-from="opacity-100 transform translate-y-0" leave-to="opacity-0 transform translate-y-4" > <div class="p-4 bg-white rounded-md shadow-sm"> {{ p.content }} </div> </TransitionRoot> </div> </TabPanel> </TabPanels> </TabGroup> </template> <script setup> import { TabGroup, TabList, Tab, TabPanels, TabPanel, TransitionRoot } from '@headlessui/vue' const panels = [ { id: 1, content: 'Tab 1 内容区域' }, { id: 2, content: 'Tab 2 内容区域' }, { id: 3, content: 'Tab 3 内容区域' }, ] </script> <style> /* 移除TabPanel的默认hidden样式 */ [data-headlessui-panel][hidden] { display: block !important; } </style>
注意:两种方案都需要确保你正确导入了TransitionRoot组件,并且配置了完整的过渡类(示例中使用Tailwind CSS类,你可以根据自己的CSS方案调整)。
内容的提问来源于stack exchange,提问作者clueless
相关产品推荐
相关产品推荐

