Как я могу перезапустить анимацию CSS со случайными значениями в цикле?

У меня есть элемент, который случайным образом анимируется с помощью CSS и JS с помощью пользовательских свойств CSS следующим образом:

var myElement = document.querySelector('#my-element');

function setProperty(number) {
  myElement.style.setProperty('--animation-name', 'vibrate-' + number);
}

function changeAnimation() {
  var number = Math.floor(Math.random() * 3) + 1;
  setProperty(number);
  /* restart the animation */
  var clone = myElement.cloneNode(true);
  myElement.parentNode.replaceChild(clone, myElement);
}

myElement.addEventListener('animationend', changeAnimation, false);
#my-element {
  width: 50px;
  height: 50px;
  background: #333;
}

 :root {
  --animation-name: vibrate-1;
}

#my-element {
  animation: 3.3s 1 alternate var(--animation-name);
}

@keyframes vibrate-1 {
  0% {
    opacity: 0;
    transform: scale(0.95);
  }
  50% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(0.9);
  }
}

@keyframes vibrate-2 {
  0% {
    opacity: 0;
    transform: scale(0.5);
  }
  50% {
    opacity: 1;
    transform: scale(0.9);
  }
  100% {
    opacity: 0;
    transform: scale(0.5);
  }
}

@keyframes vibrate-3 {
  0% {
    opacity: 0;
    transform: scale(0.3);
  }
  50% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(0.8);
  }
}
<div id = "my-element"></div>

Идея состоит в том, чтобы иметь набор анимаций, которые случайным образом переключают конец каждой анимации на другой. (что для непрозрачности в конце всегда 0, чтобы сделать плавный невидимый переключатель.)

Удивительно, но приведенный выше код работает нормально, за исключением того, что он работает только один раз, а затем останавливается.

Теперь у меня есть методы цикла JS, но я понятия не имею, как именно реализовать их в этом рабочем процессе.

Кто-нибудь может мне помочь?

У вас есть JsFiddle/Codepen этого? Или, может быть, недостающая часть HTML?

molamk 01.02.2019 08:40

@Garavani, это несколько неуместное примечание, но соглашение об именах JS - camelCase, поэтому вам следует изменить my-element на myElement.

nick zoum 01.02.2019 08:49

@nick сделал это, спасибо!

Garavani 01.02.2019 08:53
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
13
3
1 226
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Когда вы заменяете элемент клонированным элементом, вы должны переназначить прослушиватель событий animationend:

var clone = myElement.cloneNode(true);
clone.addEventListener('animationend', changeAnimation, false);
myElement.parentNode.replaceChild(clone, myElement);

Кстати, переменные в JavaScript не могут содержать -, поэтому my-element должен быть myElement.

Ответ принят как подходящий

Еще одна простая идея — положиться на animationiteration и сделать так, чтобы анимация запускалась на infinite, тогда вам больше не нужно будет клонировать элемент. Вы просто меняете имя анимации на каждой итерации, и вы получите необходимый эффект:

var myElement = document.querySelector('#my-element');

function setProperty(number) {
  myElement.style.setProperty('--animation-name', 'vibrate-' + number);
}

function changeAnimation() {
  var number = Math.floor(Math.random() * 3) + 1;
  setProperty(number);
}

myElement.addEventListener('animationiteration', changeAnimation, false);
#my-element {
  width: 50px;
  height: 50px;
  background: #333;
}

#my-element {
  animation: 3.3s alternate infinite var(--animation-name,vibrate-1);
}

@keyframes vibrate-1 {
  0% {
    opacity: 0;
    transform: scale(0.95);
  }
  50% {
    opacity: 1;
    transform: scale(1);
    background:green;
  }
  100% {
    opacity: 0;
    transform: scale(0.9);
  }
}

@keyframes vibrate-2 {
  0% {
    opacity: 0;
    transform: scale(0.5);
  }
  50% {
    opacity: 1;
    transform: scale(0.9);
    background:red;
  }
  100% {
    opacity: 0;
    transform: scale(0.5);
  }
}

@keyframes vibrate-3 {
  0% {
    opacity: 0;
    transform: scale(0.3);
  }
  50% {
    opacity: 1;
    transform: scale(1);
    background:blue;
  }
  100% {
    opacity: 0;
    transform: scale(0.8);
  }
}
<div id = "my-element"></div>

Другой способ — просто сохранить одну анимацию и настроить значения масштаба (или любые другие значения), и вы получите лучшее случайное поведение.

var myElement = document.querySelector('#my-element');

function changeAnimation() {
  var n1 = Math.random();
  myElement.style.setProperty('--s1',n1);
  var n2 = Math.random();
  myElement.style.setProperty('--s2',n2);
  var c1 = Math.floor(Math.random()*255);
  myElement.style.setProperty('--c1',c1);
  var c2 = Math.floor(Math.random()*255);
  myElement.style.setProperty('--c2',c2);
}

myElement.addEventListener('animationiteration', changeAnimation, false);
#my-element {
  width: 50px;
  height: 50px;
  background: #333;
}

#my-element {
  animation: 3.3s alternate infinite vibrate;
}

@keyframes vibrate {
  0% {
    opacity: 0;
    transform: scale(var(--s1,0.95));
  }
  50% {
    opacity: 1;
    transform: scale(1);
    background:rgb(255,var(--c1,0),var(--c2,0));
  }
  100% {
    opacity: 0;
    transform: scale(var(--s2,0.9));
  }
}
<div id = "my-element"></div>

Вау! На самом деле приведенный выше код вообще не работал. После второго запуска я боролся с этой ошибкой: TypeError: null не является объектом (оценка «myElement.parentNode.replaceChild»), вероятно, потому, что исходный элемент больше не существует. Ваш код работает намного лучше!

Garavani 01.02.2019 11:19

Я обнаружил, что во втором решении переменные на самом деле не вставляются в значения ключевого кадра. Анимация просто использует значения по умолчанию. Кажется, они не должны быть динамическими, как я прочитал здесь: stackoverflow.com/questions/18481550/… (первый ответ)

Garavani 02.02.2019 10:21

@Garavani, этот ответ не имеет ничего общего с переменной CSS. И если вы хорошо проверите анимацию, вы увидите изменение цвета, что означает изменение значения. Вот еще один пример с той же вещью, которая работает нормально: stackoverflow.com/a/49750566/8620333 ... вероятно, трудно заметить разницу в масштабе.

Temani Afif 02.02.2019 10:36

@Garavani или покажи мне код, который ты использовал, чтобы я мог увидеть проблему

Temani Afif 02.02.2019 10:40

@Garavani нет, не редактируйте вопрос, так как на самом деле на него дан ответ, и вы приняли ответ, поэтому вам следует избегать изменения значения вашего первоначального вопроса. Используйте это: jsfiddle.net и поместите туда свой код и пришлите мне ссылку

Temani Afif 02.02.2019 10:43

Вот оно: непрозрачность jsfiddle.net/yo308L7t работает, а переводы — нет. (Я также пробовал много разных способов прикрепить модуль «VW» или использовал другие устройства и т. д.)

Garavani 02.02.2019 10:55

@Garavani, вам нужно использовать calc, вы не можете выполнять умножение, как без --> calc(var(--y0) * 1vw)

Temani Afif 02.02.2019 11:02

@Garavani, вы также используете очень маленькие значения, вы ничего не заметите

Temani Afif 02.02.2019 11:06

Давайте продолжить обсуждение в чате.

Garavani 02.02.2019 11:10

Возможно, стоит отметить, что фрагмент кода № 2 не работает должным образом в Safari (12.0.3).

Garavani 02.02.2019 11:33

Другие вопросы по теме