首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >setTimeout中的setTimeout setInterval中的

setTimeout中的setTimeout setInterval中的
EN

Stack Overflow用户
提问于 2021-06-15 06:59:04
回答 3查看 76关注 0票数 2

我正在尝试制作一个字符串,它会一个字母一个字母地书写,直到完成句子,每个字母的出现速度是基于从1到10的输入。在字符串的末尾,它会闪烁5秒,直到出现一个外星人。我的想法是创建一个setInterval来添加字母,当计数器增加数组大小时,它将使用新的setInterval调用返回循环的最终动画,在再次调用它之前,它已经被清除,并通过setTimout回调在递归中再次调用,以维护无限循环。但是它没有到达setTimout,为什么?

//script.js

代码语言:javascript
复制
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

代码语言:javascript
复制
<!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

代码语言:javascript
复制
*,
*::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;
  }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-06-15 09:25:14

还有animation frame api

它会在浏览器的下一次“自然”重绘之前运行你的函数。

此外,它将在回调中传递当前时间,因此您可以获取时间细节并根据此设置动画。这样,即使帧速率不一致,也可以为每个人获得相同长度的平滑动画。

考虑下面的代码片段,它基本上会导致无限循环。

代码语言:javascript
复制
function draw(now) {
   requestAnimationFrame(draw)
}

requestAnimationFrame(draw)

现在,您只需记住时间,并在下次调用函数时获取时间增量。如果经过了足够的时间,您可以编写另一个字符。(通常,您将更改除以时间增量的值,但由于您有字符,因此它们要么在那里,要么不在。

代码语言:javascript
复制
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。这样就可以取消循环。

代码语言:javascript
复制
const frameId = requestAnimationFrame(draw)
cancelAnimationFrame(frameId)

因此,最终的代码可能如下所示。

代码语言:javascript
复制
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)
代码语言:javascript
复制
<p></p>

票数 2
EN

Stack Overflow用户

发布于 2021-06-15 07:37:40

问题是,在else语句中,您将返回一个从未调用过的函数。

代码语言:javascript
复制
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函数即可。

代码语言:javascript
复制
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)
票数 0
EN

Stack Overflow用户

发布于 2021-06-15 08:30:39

我找到了解决方案。使用setInterval,代码创建了多个回调实例并重载了内存。

/script.js

代码语言:javascript
复制
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);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67978080

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档