Как я могу перезапустить переход CSS, как только он закончится, используя стандартный JavaScript? - PullRequest
2 голосов
/ 14 марта 2020

Я построил своего рода генератор паролей, который должен отображать новый пароль всякий раз, когда заканчивается обратный отсчет. К сожалению, мне удалось выяснить, как запустить мой код один раз. Обратный отсчет состоит из простого CSS перехода, который я хотел бы сохранить, потому что он намного более плавный, чем другие мои попытки, в котором я пытался многократно обновлять ширину, используя JavaScript.

var dictionary = {
	"adverbs": [
  	"always",
  	"usually",
    "probably"
  ],
  "adjectives": [
  	"useful",
  	"popular",
   	"accurate"
  ],
  "nouns": [
  	"computer",
    "software",
    "terminal"
  ]
};

function capitalizeFirst(string) {
	return string.charAt(0).toUpperCase() + string.slice(1);
}

function randomIndex(object) {
	return object[Math.floor(Math.random() * object.length)];
}

function generatePassword() {
	var category = ["adverbs", "adjectives", "nouns"];
	var password = [];
  
  for (i = 0; i < category.length; i++) {
  	password.push(capitalizeFirst(randomIndex(dictionary[category[i]])));
  }
  
  password.push(Math.floor(Math.random() * 8999) + 1000);
  return password.join("");
}

function updatePassword() {
	document.getElementById("countdown-fill").style.width = 100 + '%';
	document.getElementById("text-field").value = generatePassword();
	document.getElementById("countdown-fill").style.width = 0 + '%';
}

setInterval(updatePassword, 5000);
@import url('https://fonts.googleapis.com/css?family=Nunito&display=swap');

body {
  margin: 0;
  width: 100%;
  height: 100%;
  background-color: #f8f8f8;
}

.container {
  max-width: 400px;
  margin: 0 auto;
}

#text-field {
  font-size: 15px;
  font-weight: 400;
  font-family: 'Nunito', sans-serif;
  margin-top: 100px;
  margin-bottom: 10px;
  width: 100%;
  height: 30px;
  padding: 10px;
  box-sizing: border-box;
  border: 1px solid  #e5e5e5;
  background-color: #ffffff;
}

#countdown-background {
  width: 100%;
  height: 10px;
  box-sizing: border-box;
  border: 1px solid  #e5e5e5;
  background-color: #ffffff;
}
#countdown-fill {
  width: 100%;
  height: 100%;
  transition: width 5s;
  transition-timing-function: linear;
  background-color: #1e87f0;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Password Generator</title>
  </head>
  <body>
    <div class="container">
      <input id="text-field" type="text" spellcheck="false">
      <div id="countdown-background">
        <div id="countdown-fill"></div>
      </div>
    </div>
  </body>
</html>

В настоящее время у меня есть две очевидные проблемы с моим кодом:

  1. Переход задерживается из-за setInterval , Это не тот случай, если я просто вызываю updatePassword самостоятельно.
  2. Переход CSS анимируется только один раз. Я хотел бы сбрасывать анимацию каждый раз, когда звоню updatePassword.

. Я нашел несколько jQuery решений для моей проблемы, но я не очень заинтересован в них, так как хочу полагаться на стандарт JavaScript в максимально возможной степени. Тем не менее, я в порядке с альтернативными CSS инструментами, такими как ключевые кадры, которые, кажется, работают хорошо:

#countdown-fill {
  width: 100%;
  height: 100%;
  animation: refresh 5s infinite;
  background-color: #1e87f0;
}

@keyframes refresh {
    from {
        width: 100%;
    }
    to {
        width: 0;
    }
}

Хотя, я действительно беспокоюсь о проблемах синхронизации, так как анимация никак не связана с updatePassword .

Вопрос: Есть ли способ updatePassword сбрасывать анимацию при каждом вызове функции и удалять начальную задержку?

JSFiddle : https://jsfiddle.net/MajesticPixel/fxkng013/

Ответы [ 2 ]

3 голосов
/ 14 марта 2020

Я изменил ваш JSFiddle , вот объяснение.

#countdown-fill {
  width: 100%;
  height: 100%;
  transform-origin: left;
  background-color: #1e87f0;
}
.reset {
  transition: transform 5s linear;
  transform: scaleX(0);
}

Хитрость заключается в том, чтобы связать переход с классом, и когда вы хотите сбросить его, вы просто удаляете класс (сбросьте переход к исходному состоянию) и добавьте его снова (перезапустите).

Но есть несколько ошибок: самое важное, что мгновенное удаление и добавление класса будет оптимизировано браузером , который просто объединит действия и никакого перехода вообще не произойдет. Хитрость заключается в том, чтобы обернуть вызовы во вложенный вызов rAF, что заставит браузер выполнить, отобразить и снова выполнить.

window.requestAnimationFrame(function() {
  document.getElementById("countdown-fill").classList.remove('reset');   
  window.requestAnimationFrame(function() {
    document.getElementById("countdown-fill").classList.add('reset');
  });
});

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

1 голос
/ 14 марта 2020

Я второй, что опубликовал NevNein, и также хотел бы добавить, что если вы хотите связать переход с updatePassword, чтобы они имели взаимосвязанные отношения, а не просто совпадающие тайм-ауты, вы должны заменить setInterval(updatePassword, 5000) на:

updatePassword();
document.getElementById('countdown-fill').addEventListener("transitionend", updatePassword)

Обратный отсчет и смена пароля теперь будут выполняться на любой скорости, установленной в CSS.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...