首页 > 解决方案 > 使用标准 JavaScript 结束后,如何重新启动 CSS 过渡?

问题描述

我已经构建了一种密码生成器,它应该在倒计时到期时显示一个新密码。不幸的是,我只设法弄清楚如何运行我的代码一次。倒计时由一个简单的 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/

标签: javascriptcss

解决方案


我已经修改了你的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');
  });
});

第二个与过渡有关:优化浏览器渲染,避免过渡属性如宽度或高度,并尝试限制变换和不透明度。我已将您的宽度过渡更改为变换过渡:效果相同,性能更高。


推荐阅读