我正在尝试制作一个字符串,它会一个字母一个字母地书写,直到完成句子,每个字母的出现速度是基于从1到10的输入。在字符串的末尾,它会闪烁5秒,直到出现一个外星人。我的想法是创建一个setInterval来添加字母,当计数器增加数组大小时,它将使用新的setInterval调用返回循环的最终动画,在再次调用它之前,它已经被清除,并通过setTimout回调在递归中再次调用,以维护无限循环。但是它没有到达setTimout,为什么?
//script.js
const speedInput = document.getElementsByClassName('speed--input')[0];
const alien = document.getElementsByClassName('alien')[0];
const textDiv = document.getElementsByClassName('text')[0];
const textShow = document.getElementsByClassName('text--show')[0];
const textDB = 'We go to dominate the world.';
const textStr = '';
let count = 0;
let speed = speedInput.value * 100;
const textChangeHandle = (count, textStr, textDB) => setInterval(() => {
if (count < textDB.length) {
textStr += textDB[count];
textShow.innerHTML = textStr;
textDiv.style.width = `${40 * count}px`;
count++;
} else {
textShow.style.animation = 'bip 1s linear 1s infinite'
return () => {
setTimeout(() => {
textShow.style.animation = '';
textStr = '';
count = 0;
textShow.style.opacity = 0;
alien.style.opacity = 1;
setTimeout(() => {
alien.style.opacity = 0;
textShow.style.opacity = 1;
textChangeHandle(count, textStr, textDB)
}, 5000)
}, 5000);
clearInterval(textChangeHandle);
}
}
}, speed)
textChangeHandle(count, textStr, textDB);//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style/style.css">
<title>Document</title>
</head>
<body>
<div class="text">
<p class="text--show"></p>
<img class="alien" src="alien.png" alt="Aki é Jupiter karai">
</div>
<div class="speed">
<span>Speed</span>
<input class="speed--input" type="number" min="1" max="10" value="1">
</div>
<script src="script.js"></script>
</body>
</html>//style.css
*,
*::after,
*::before {
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
body {
font-family: sans-serif;
background-color: #3cd070;
}
.text {
position: fixed;
top: 50%;
left: 50%;
height: auto;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
font-size: 40px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.text .alien {
opacity: 0;
height: 600px;
width: auto;
margin-bottom: 50px;
position: absolute;
}
.text .text--show {
font-size: 40px;
width: 100%;
position: absolute;
display: block;
text-align: center;
-webkit-animation: bip 1s linear 1s infinite;
animation: bip 1s linear 1s infinite;
}
.speed {
position: fixed;
top: 90%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.2);
display: -webkit-box;
display: -ms-flexbox;
display: flex;
padding: 10px 20px;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
.speed .speed--input {
border: 0;
outline: 0;
width: 40px;
height: 25px;
margin: 10px;
text-align: center;
}
@-webkit-keyframes bip {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes bip {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}发布于 2021-06-15 09:25:14
它会在浏览器的下一次“自然”重绘之前运行你的函数。
此外,它将在回调中传递当前时间,因此您可以获取时间细节并根据此设置动画。这样,即使帧速率不一致,也可以为每个人获得相同长度的平滑动画。
考虑下面的代码片段,它基本上会导致无限循环。
function draw(now) {
requestAnimationFrame(draw)
}
requestAnimationFrame(draw)现在,您只需记住时间,并在下次调用函数时获取时间增量。如果经过了足够的时间,您可以编写另一个字符。(通常,您将更改除以时间增量的值,但由于您有字符,因此它们要么在那里,要么不在。
let speed = 300
let timePassedSinceLastChar = 0
let then = null
function draw(now){
now *= 0.001;
const deltaTime = now - then;
then = now;
timePassedSinceLastChar += deltaTime;
if (timePassedSinceLastChar >= speed) {
drawChar()
timePassedSinceLastChar = 0
}
requestAnimationFrame(draw)
}
requestAnimationFrame(draw)此外,requestAnimationFrame函数返回所请求帧的id。这样就可以取消循环。
const frameId = requestAnimationFrame(draw)
cancelAnimationFrame(frameId)因此,最终的代码可能如下所示。
const textDB = 'We go to dominate the world.';
let charIndex = 0;
let frameId = null
let then = 0
let sinceDraw = 0
let speed = () => Math.random() * 0.4 + 0.05 // randomize the speed a bit
let $p = document.querySelector('p')
function draw(now) {
// cancel on end of string
if (charIndex >= textDB.length) {
cancelAnimationFrame(frameId)
console.log('done')
return
}
// get the time delta
now *= 0.001; // convert to seconds
const deltaTime = now - then;
then = now;
sinceDraw += deltaTime
// if its time to draw again, do so
if (sinceDraw >= speed()) {
let char = textDB[charIndex]
$p.textContent += char
charIndex++
sinceDraw = 0
}
// request another frame
frameId = requestAnimationFrame(draw)
}
// request the first frame
frameId = requestAnimationFrame(draw)<p></p>
发布于 2021-06-15 07:37:40
问题是,在else语句中,您将返回一个从未调用过的函数。
return () => {
setTimeout(() => {
textShow.style.animation = '';
textStr = '';
count = 0;
textShow.style.opacity = 0;
alien.style.opacity = 1;
setTimeout(() => {
alien.style.opacity = 0;
textShow.style.opacity = 1;
textChangeHandle(count, textStr, textDB)
}, 5000)
}, 5000);
clearInterval(textChangeHandle);
}只需删除返回语句,直接调用setTimeout函数即可。
const textChangeHandle = (count, textStr, textDB) => setInterval(() => {
if (count < textDB.length) {
textStr += textDB[count];
textShow.innerHTML = textStr;
textDiv.style.width = `${40 * count}px`;
count++;
} else {
textShow.style.animation = 'bip 1s linear 1s infinite'
setTimeout(() => {
textShow.style.animation = '';
textStr = '';
count = 0;
textShow.style.opacity = 0;
alien.style.opacity = 1;
setTimeout(() => {
alien.style.opacity = 0;
textShow.style.opacity = 1;
textChangeHandle(count, textStr, textDB)
}, 5000)
}, 5000);
clearInterval(textChangeHandle);
}
}, speed)发布于 2021-06-15 08:30:39
我找到了解决方案。使用setInterval,代码创建了多个回调实例并重载了内存。
/script.js
const textEl = document.getElementById('text');
const inputEl = document.getElementById('input');
const alienEl = document.getElementById('alien');
const text = 'We go to dominate the world!';
let idx = 0;
let speed = 300 / inputEl.value;
writeText();
function writeText () {
if(idx === 0) setTimeout(() => textEl.style.opacity = 1, speed)
textEl.innerText = text.slice(0, idx);
idx++;
if (idx > text.length) {
idx = 0;
textEl.style.animation = 'bip 1s linear 1s infinite';
setTimeout(() => {
textEl.style.animation = ''
textEl.style.opacity = 0;
setTimeout(() => {
alienEl.style.opacity = 1;
setTimeout(() => {
alienEl.style.opacity = 0;
setTimeout(writeText, speed);
}, 5000)
}, 1000);
}, 5000)
} else {
setTimeout(writeText, speed);
}
}
inputEl.addEventListener('input', (e) => speed = 300 / e.target.value);https://stackoverflow.com/questions/67978080
复制相似问题