如何从香草JS中的元素中删除CSS动画

时间:2019-05-27 06:06:01

标签: javascript css

我有一个n×n个较小的div元素的正方形网格,我想用CSS背景颜色动画按顺序进行照明。我有一个函数可以为序列生成随机数组。我遇到的麻烦是一旦某个正方形被照亮了一次,如果它再次出现在阵列中,它将不会再次亮起。我相信这是因为一旦为元素分配了CSS动画,该动画就无法在该元素上再次触发,而且我也无法找到使它起作用的方法。这是我正在参加的响应式Web应用程序课程,并且评估规定我们仅使用香草JS,并且所有元素都必须在JS中创建并附加到index.html中的空白<body>

每个序列的闪光都是通过setTimeout函数触发的,该函数循环遍历数组中的所有元素,从而使每个循环的计时器增加1s(动画长度也为1s)。

定义容器和子div:

function createGameContainer(n, width, height) {
    var container = document.createElement('div');

    //CSS styling
    container.style.margin = '50px auto'
    container.style.width = width;
    container.style.height = height;
    container.style.display = 'grid';

    // loop generates string to create necessary number of grid columns based on the width of the grid of squares
    var columns = '';
    for (i = 0; i < n; i++) {
        columns += ' calc(' + container.style.width + '/' + n.toString() + ')'
    }
    container.style.gridTemplateColumns = columns;

    container.style.gridRow = 'auto auto';

    // gap variable to reduce column and row gap for larger grid sizes
    // if n is ever set to less than 2, gap is hardcoded to 20 to avoid taking square root of 0 or a negative value
    var gap;
    if (n > 1) {
        gap = 20/Math.sqrt(n-1);
    } else {
        gap = 20;
    }

    container.style.gridColumnGap = gap.toString() + 'px';
    container.style.gridRowGap = gap.toString() + 'px';

    container.setAttribute('id', 'game-container');

    document.body.appendChild(container);
}


/*
function to create individual squares to be appended to parent game container
*/
function createSquare(id) {
    var square = document.createElement('div');

    //CSS styling
    square.style.backgroundColor = '#333';
    //square.style.padding = '20px';
    square.style.borderRadius = '5px';
    square.style.display = 'flex';
    square.style.alignItems = 'center';
    //set class and square id
    square.setAttribute('class', 'square');
    square.setAttribute('id', id);

    return square;
}
/*
function to create game container and and squares and append squares to parent container
parameter n denotes dimensions of game grid - n x n grid
*/

function createGameWindow(n, width, height) {
    window.dimension = n;
    createGameContainer(n, width, height);

    /*
    loop creates n**2 number of squares to fill game container and assigns an id to each square from 0 at the top left square to (n**2)-1 at the bottom right square
    */
    for (i = 0; i < n**2; i++) {
        var x = createSquare(i);
        document.getElementById('game-container').appendChild(x);
    }
}

CSS动画

@keyframes flash {
    0% {
        background: #333;
    }

    50% {
        background: orange
    }

    100% {
        background: #333;
    }
}

.flashing {
    animation: flash 1s;
}

生成数组的代码:

function generateSequence(sequenceLength) {
    var sequence = [];
    for (i = 0; i < sequenceLength; i++) {
        var random = Math.floor(Math.random() * (dimension**2));
        // the following loop ensures each element in the sequence is different than the previous element
        while (sequence[i-1] == random) {
            random = Math.floor(Math.random() * (dimension**2));
        }
        sequence[i] = random;
    };

    return sequence;
}

将动画应用于正方形的代码:

function flash(index, delay) {
    setTimeout( function() {
        flashingSquare = document.getElementById(index);
        flashingSquare.style.animation = 'flashOne 1s';
        flashingSquare.addEventListener('animationend', function() {
            flashingSquare.style.animation = '';
    }, delay);    
}

我也尝试过再次删除并添加一个类以尝试重置动画:

function flash(index, delay) {
    setTimeout( function() {
        flashingSquare = document.getElementById(index);
        flashingSquare.classList.remove('flashing');
        flashingSquare.classList.add('flashing');
    }, delay);    
}

生成和显示序列的功能:

function displaySequence(sequenceLength) {
    var sequence = generateSequence(sequenceLength);

    i = 0;
    while (i < sequence.length) {
        index = sequence[i].toString();
        flash(index, i*1000);

        i++;
    }
}

尽管进行了许多不同的尝试和大量研究,但我仍然找不到让动画在同一元素上多次触发的方法。

2 个答案:

答案 0 :(得分:0)

尝试这个:

function flash(index, delay){
    setTimeout( function() {
        flashingSquare = document.getElementById(index);
        flashingSquare.classList.add('flashing');
        flashingSquare.addEventListener('animationend', function() {
                flashingSquare.classList.remove('flashing');
        }, delay);    
    });
}

不删除动画,删除课程

删除课程直接后,动画就完成了。因此,浏览器有时间处理所有事情。并且,当您添加类直接之前所需的动画时,浏览器可以触发所有需要的步骤来实现。

您尝试删除和添加类的尝试很好,但是速度很快。我认为浏览器和DOM可优化您的步骤,而无济于事。

答案 1 :(得分:0)

经过研究,我找到了解决方法。我重写了函数,以便setTimeout嵌套在for循环中,而setTimeout嵌套在立即调用的函数表达式中(我仍然不完全了解,但是,如果可以的话)。新功能如下:

/*
function to display game sequence
length can be any integer greater than 1
speed is time between flashes in ms and can presently be set to 1000, 750, 500 and 250.
animation length for each speed is set by a corresponding speed class
in CSS main - .flashing1000 .flashing750 .flashing500 and .flashing250
*/
function displaySequence(length, speed) {
    var sequence = generateSequence(length);
    console.log(sequence);

    for (i = 0; i < sequence.length; i++) {
        console.log(sequence[i]);
        //       immediately invoked function expression
        (function(i) {
            setTimeout( function () {
                var sq = document.getElementById(sequence[i]);
                sq.classList.add('flashing' + speed.toString());
                sq.addEventListener('animationend', function() {
                    sq.classList.remove('flashing' + speed.toString());
                })
            }, (speed * i))
        })(i);
    }
}

每个类的CSS:

@keyframes flash {
    0% {
        background: #333;
    }

    50% {
        background: orange
    }

    100% {
        background: #333;
    }
}

.flashing1000 {
    animation: flash 975ms;
}

.flashing750 {
    animation: flash 725ms;
}

.flashing500 {
    animation: flash 475ms;
}

.flashing250 {
    animation: flash 225ms;
}

我知道有一些懒惰的解决方法,但是效果很好。