使用 class 在每个元素上键入动画

typing animation on each element with its class

我正在尝试制作打字动画,但它不起作用,我也不知道为什么。我知道我可以在 CSS 中完成,但我想在 JS 中尝试。问题可能是函数本身我不是 JS 中最好的。

<p class="typing-animation">this will be animated</p>
<p class="typing-animation">this aswell</p>
<script>
const sleep = (ms) => {
  return new Promise((resolve) => setTimeout(resolve, ms));
};

const toType = document.getElementsByClassName("typing-animation");

document.getElementsByClassName("typing-animation").textContent = "";

(async (toType) => {
  for (let each of toType) {
    text = each.textContent;
    each.textContent = "";
    let i = 0;
    for (let every of text) {
      every.textContent += text[i];
      await sleep(200);
      i++;
    }
  }
})(toType);
</script>

你走在正确的道路上。为了便于阅读,我刚刚清理了一些内容。

这是它的一个代码框:https://codesandbox.io/s/typing-animation-kdn8v

我假设您希望动画并行发生。出于这个原因,我们希望 运行 遍历每个 HTML 元素并在每个元素上调用我们的 animateType 函数而不等待。

每次调用 animateType 都意味着此 HTML 元素有此函数 运行ning 的副本。这样,函数内部的 text 等变量就不会在 HTML 元素之间混淆。这称为“关闭”。函数“实例”内的所有变量,仅存在于该函数实例内。

我们存储原始文本,然后清除 HTML 元素的内容,然后就像您所做的一样,我们循环缓存文本的字母,并将每个字母添加到 HTML 元素。

// Whosebug: 

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const clearAndCache = (elements) => {
  let cachedText = [];
  for (let element of elements) {
    cachedText.push(element.textContent);
    element.textContent = "";
  }
  return cachedText;
};

const animateTypeSync = async (typeables, ms) => {
  const cachedText = clearAndCache(typeables);

  for (let i = 0; i < typeables.length; i++) {
    for (let character of cachedText[i]) {
      typeables[i].textContent += character;
      await sleep(ms);
    }
  }
};

const animateTypeAsync = (typeables, ms) => {
  const cachedText = clearAndCache(typeables);

  Array.from(typeables).forEach(async (element, i) => {
    for (let character of cachedText[i]) {
      element.textContent += character;
      await sleep(ms);
    }
  });
};

const elementsSync = document.getElementsByClassName("typing-animation-sync");
animateTypeSync(elementsSync, 200);

const elementsAsync = document.getElementsByClassName("typing-animation");
animateTypeAsync(elementsAsync, 150);
<!DOCTYPE html>
<html>
  <head>
<title>Typing Animation</title>
<meta charset="UTF-8" />
  </head>

  <body>
<h1>Typing Animations</h1>

<div style="width: 100%; display: inline-flex;">
  <div style="width: 50%;">
    <h2>Async</h2>
    <p class="typing-animation">These will run</p>
    <p class="typing-animation">at the same time</p>
  </div>

  <div style="width: 50%;">
    <h2>Sync</h2>
    <p class="typing-animation-sync">These will animate</p>
    <p class="typing-animation-sync">one at a time</p>
  </div>
</div>
  </body>
  <script src="src/index.js"></script>
</html>

编辑:在 OP 发表评论后将同步版本添加到代码中。

我想这就是你想要的?

<p class="typing-animation">this will be animated</p>
<p class="typing-animation">this aswell</p>

<script>
const sleep = (ms) => {
  return new Promise((resolve) => setTimeout(resolve, ms));
};

// This is an array of html elements, since getElementsByClassName returns an array, since there can be more than one html element with that class.
const elements = document.getElementsByClassName("typing-animation");

(async (typedElements) => {
   let texts = []
   
   for (let element of typedElements){
    // The property to access the text inside the elements .innerHTML, if its a user interactuable element such as <input> or <textarea> then its .value
    texts.push(element.innerHTML);
    element.innerHTML = "";
   }
   
   // texts and typedElements has the same length.
   for (let i = 0; i < texts.length; i++) {
      for (let character of texts[i]) {
        typedElements[i].innerHTML += character;
        await sleep(200)
      } 
   }
  
})(elements);
</script>

如果你想在多个地方实现这种效果,并且更容易实现,有一个库已经做到了,更容易定制和使用:Typed.js

<span class="typed"></span>

<script src="https://cdn.jsdelivr.net/npm/typed.js@2.0.12"></script>

<script>
  // For more examples check: https://github.com/mattboldt/typed.js
  // Full docs at: https://mattboldt.github.io/typed.js/docs/
  const options = {
    strings: ['This will be typed!', 'This too! ^500 <br> And this will go under!'],
    typeSpeed: 40,
    backSpeed: 40,
    backDelay: 2000,
  };
  
  // We'll bind the typing animation to the .typed class.
  let typed = new Typed('.typed', options);
</script>