Vue.js切换暗黑模式时过渡动画中断问题求助
为什么Vue中computed写法无法触发暗黑开关的CSS过渡动画?
我在App.vue中引入了自定义组件DarkSwitch.vue,该组件会为html元素添加.dark类,但切换暗黑模式时,开关的过渡动画会被中断。使用watch配合nextTick的临时方案可以解决此问题:
const isDarkClass = ref(""); watch(isDark, async () => { await nextTick(); isDarkClass.value = isDark.value ? "translate-x-5" : "translate-x-0"; });
但使用computed的写法无法正常触发CSS过渡,代码如下:
<script setup> import { useDark, useToggle } from "@vueuse/core"; import { computed } from "vue"; let isDark = useDark(); const toggleDark = useToggle(isDark); const isDarkClass = computed(() => { return isDark.value ? "translate-x-5" : "translate-x-0"; }); </script> <template> <button type="button" class="relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent bg-purple transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2 dark:bg-green" role="switch" @click="toggleDark()" > <span aria-hidden="true" class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out" :class="isDarkClass" ></span> </button> </template>
原因分析
核心问题在于useDark()的状态更新和DOM上.dark类的添加是同步发生的,而computed会在isDark状态变化时立即更新开关的translate类名——这导致两个DOM样式变更(添加.dark类、修改开关位移类)在同一个Vue更新周期内完成。浏览器会把同周期内的DOM变更合并成一次重排/重绘,直接计算最终的DOM状态,跳过了从初始位移到目标位移的中间过程,自然无法触发CSS过渡动画。
而watch配合nextTick的方案,是把开关类名的更新推迟到下一个DOM更新周期:当isDark变化后,先等待Vue完成.dark类的DOM注入(nextTick会等待当前周期所有DOM操作执行完毕),再修改开关的位移类。这样浏览器会把这两个操作拆分成两次独立的重排/重绘,能清晰识别到位移样式的前后变化,从而正常触发过渡动画。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

