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

JS中mouseenter触发但CSS动画仅执行一次问题求助

解决CSS Keyframes动画仅首次mouseenter触发的问题

问题原因

直接通过element.style.animation设置动画时,动画执行完毕后该属性仍保留在元素的行内样式中。再次触发mouseenter事件时,设置相同的动画属性值,浏览器会判定属性未发生变化,因此不会重新启动动画。

解决方案

方法一:重置行内动画属性后重新触发

每次触发事件时,先清除元素的动画属性,强制浏览器重绘后再重新设置动画:

const notes_animation = document.querySelectorAll(".note");

for (let i = 0; i < notes_animation.length; i++) {
    notes_animation[i].addEventListener('mouseenter', function() {
        const dot = this.querySelector(".backgr_color");
        
        // 清除现有动画
        dot.style.animation = 'none';
        // 强制浏览器重绘,确保样式更新生效
        void dot.offsetHeight;
        // 重新设置动画
        dot.style.animation = "animate_notes 2500ms ease";

        // 批量处理文本类元素
        const animateTargets = [
            this.querySelector(".note_text"),
            this.querySelector(".note_comment"),
            this.querySelector(".note_bottom")
        ];

        animateTargets.forEach(el => {
            el.style.animation = 'none';
            void el.offsetHeight;
            el.style.animation = "animate_text 2700ms ease";
        });
    });
}

方法二:使用CSS类控制动画(推荐)

将动画逻辑封装到CSS类中,通过添加/移除类来触发动画,同时配合animationend事件自动清理类:

  1. 首先定义CSS类:
.animate-notes {
    animation: animate_notes 2500ms ease;
}

.animate-text {
    animation: animate_text 2700ms ease;
}
  1. 然后修改JavaScript代码:
const notes_animation = document.querySelectorAll(".note");

notes_animation.forEach(note => {
    note.addEventListener('mouseenter', function() {
        const dot = this.querySelector(".backgr_color");
        // 先移除类,强制重绘后再添加
        dot.classList.remove('animate-notes');
        void dot.offsetHeight;
        dot.classList.add('animate-notes');

        const textElements = [
            this.querySelector(".note_text"),
            this.querySelector(".note_comment"),
            this.querySelector(".note_bottom")
        ];

        textElements.forEach(el => {
            el.classList.remove('animate-text');
            void el.offsetHeight;
            el.classList.add('animate-text');
        });
    });

    // 监听动画结束事件,自动移除类避免冲突
    const dot = note.querySelector(".backgr_color");
    dot.addEventListener('animationend', () => dot.classList.remove('animate-notes'));
    
    note.querySelectorAll(".note_text, .note_comment, .note_bottom").forEach(el => {
        el.addEventListener('animationend', () => el.classList.remove('animate-text'));
    });
});

关键说明

void el.offsetHeight的作用是强制浏览器立即计算元素的布局信息,触发重绘。如果省略这一步,浏览器可能会把"移除属性/类 + 添加属性/类"的操作合并成一次,导致无法检测到样式变化,动画也就不会重新触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 14:28:12