如何使用settimeout依次实现两个打字机效果,从而通过延迟​​字符和延迟行通过延迟字符打印行字符?

发布于 2025-02-03 12:28:31 字数 1248 浏览 4 评论 0原文

我正在尝试建立一种方法,以使网站上的多条字符串“键入”。我一直在为每一行编写一个新功能,但是现在我试图设置一个函数以循环循环通过一系列字符串,然后在新行中键入每个字符串。但是,我无法正确暂停,只能获得第一个字符串,而第三字符串的一部分则可以实际输入。有没有更好的方法来计算超时,或者有一种更好的方法可以使功能连续运行而不是同时运行?我正在尝试坚持使用香草JavaScript,所以请不要jQuery。

var typeSpeed = 75;
var newSpan = '<span></span><br>';

function newTextSegment() {
  i = 0;
  j = 0;
  stringsArray = ['Type Line 1.', 'Type Line 2.', 'Type Line 3.'];
  arrayLength = stringsArray.length;
  typeLinesConsecutively();
}

function typeLinesConsecutively() {
  if (j < arrayLength) {
    segmentString = stringsArray[j];
    delay = segmentString.length * typeSpeed;

    document.querySelector('body').insertAdjacentHTML('beforeend', newSpan);

    typewriter();

    j++;

    setTimeout(typeLinesConsecutively, delay);
  }
}

//This is the function that will type out letter by letter
function typewriter() {
  var allSpan = document.querySelectorAll('span');
  if (i < segmentString.length) {
    allSpan[allSpan.length - 1].innerHTML += segmentString.charAt(i);
    i++;
    setTimeout(typewriter, typeSpeed);
  }
}

window.onload = (event) => {
  console.log('page loaded');
  newTextSegment();
};

I'm trying to build out a way to have multiple lines of strings "typed" out on a website. I've been writing a new function for every line, but now I'm trying to setup one function to loop through an array of strings, and type each string out on a new line. However, I can't get the timeouts right and only get the first string, and part of the 3rd string to actually type out. Is there a better way to calculate the timeouts, or a better way to get the functions to run consecutively rather than at the same time? I'm trying to stick with vanilla javascript, so no jquery please.

var typeSpeed = 75;
var newSpan = '<span></span><br>';

function newTextSegment() {
  i = 0;
  j = 0;
  stringsArray = ['Type Line 1.', 'Type Line 2.', 'Type Line 3.'];
  arrayLength = stringsArray.length;
  typeLinesConsecutively();
}

function typeLinesConsecutively() {
  if (j < arrayLength) {
    segmentString = stringsArray[j];
    delay = segmentString.length * typeSpeed;

    document.querySelector('body').insertAdjacentHTML('beforeend', newSpan);

    typewriter();

    j++;

    setTimeout(typeLinesConsecutively, delay);
  }
}

//This is the function that will type out letter by letter
function typewriter() {
  var allSpan = document.querySelectorAll('span');
  if (i < segmentString.length) {
    allSpan[allSpan.length - 1].innerHTML += segmentString.charAt(i);
    i++;
    setTimeout(typewriter, typeSpeed);
  }
}

window.onload = (event) => {
  console.log('page loaded');
  newTextSegment();
};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

生生漫 2025-02-10 12:28:31

OP的递归延迟功能的方法可以完全坚持一个任务,然后需要以所有逻辑(是否呈现新线路和/或键入新字符)的方式实现,该任务必须由它。

为了提供解决方案和特定特定任务的解决方案,必须选择一种较高抽象的方法。

下一个提供的一个基于两个一般实现的函数...

重复使用这两个函数两次启用一个解决方案,该解决方案迭代延迟line值(具有新的行延迟),每行迭代迭代延迟char> char> char values(带有特定于字符的特定于字符) (键入)延迟)两次通过 for-wait ... 。

来调用这两个功能

  • 设置
  • 可以使用
  • 可选的
async function* createDeferredValuesPool(asyncFunctions) {
  let asyncFct;
  while (asyncFct = asyncFunctions.shift()) {

    yield (await asyncFct());
  }
}
function createDeferredValueAction(value, delay) {
  return async function () {
    return await (
      new Promise(resolve => setTimeout(resolve, delay, value))
    );
  }
}

async function typeLine(rootNode, line, lineTemplate, charDelay) {
  rootNode
    .insertAdjacentHTML('beforeend', lineTemplate);

  const lineNode = [...rootNode
    .querySelectorAll('[data-line-content]')
  ]
  .slice(-1)[0]; // instead of the not entirely supported `.at(-1)`.

  const deferredCharacterActions = line
    .split('')
    .map(char =>
      createDeferredValueAction(char, charDelay)
    );
  const deferredCharactersPool =
    createDeferredValuesPool(deferredCharacterActions);

  for await (const char of deferredCharactersPool) {
    lineNode.textContent = lineNode.textContent + char;
  }
}
async function typeLines(
  rootNode = document.body,
  lines = [],
  lineTemplate = '<p data-line-content></p>',
  lineDelay = 200,
  charDelay = 10,
) {
  const deferredNewLineActions = lines
    .map(line =>
      createDeferredValueAction(line, lineDelay)
    );
  const deferredNewLinesPool =
    createDeferredValuesPool(deferredNewLineActions);

  for await (const line of deferredNewLinesPool) {

    await typeLine(rootNode, line, lineTemplate, charDelay);
  }
}

(async () => {
  await typeLines(
    document.body,
    ['Type Line 1.', 'Type Line 2.', 'Type Line 3.'],
    '<span data-line-content></span><br>',
    400,
    30,
  );
  await typeLines(
    document.body,
    ['And 2 lines, created by ...', '... default type-settings.'],
  );
})();

The OP's approach of a recursively delayed function forces one to stick to exactly a single task which then needs to be implemented in a way that all logic (whether to render a new line and/or to type a new character) has to be carried by it.

In order to provide a solution with line and character specific tasks one has to choose an approach of higher abstraction.

The next provided one is based on two generically implemented functions ...

  • the first one creating an async function which returns any provided value with a value specific delay (deferred value) based on resolving a Promise,
  • and the second one being an asynchronous generator function which creates an async generator of deferred values from a list/array of async functions which each returns a deferred value.

Re-using this two functions twice enables a solution which iterates deferred line values (with a new line specific delay) and for each line iterates deferred char values (with a character specific (typing) delay) both times by for-await...of.

Both functions can be invoked with optional settings for e.g.

  • a specific root node,
  • a custom line-template (provided as markup string),
  • custom delays (in msecs) for either new line- and/or character-insertion

async function* createDeferredValuesPool(asyncFunctions) {
  let asyncFct;
  while (asyncFct = asyncFunctions.shift()) {

    yield (await asyncFct());
  }
}
function createDeferredValueAction(value, delay) {
  return async function () {
    return await (
      new Promise(resolve => setTimeout(resolve, delay, value))
    );
  }
}

async function typeLine(rootNode, line, lineTemplate, charDelay) {
  rootNode
    .insertAdjacentHTML('beforeend', lineTemplate);

  const lineNode = [...rootNode
    .querySelectorAll('[data-line-content]')
  ]
  .slice(-1)[0]; // instead of the not entirely supported `.at(-1)`.

  const deferredCharacterActions = line
    .split('')
    .map(char =>
      createDeferredValueAction(char, charDelay)
    );
  const deferredCharactersPool =
    createDeferredValuesPool(deferredCharacterActions);

  for await (const char of deferredCharactersPool) {
    lineNode.textContent = lineNode.textContent + char;
  }
}
async function typeLines(
  rootNode = document.body,
  lines = [],
  lineTemplate = '<p data-line-content></p>',
  lineDelay = 200,
  charDelay = 10,
) {
  const deferredNewLineActions = lines
    .map(line =>
      createDeferredValueAction(line, lineDelay)
    );
  const deferredNewLinesPool =
    createDeferredValuesPool(deferredNewLineActions);

  for await (const line of deferredNewLinesPool) {

    await typeLine(rootNode, line, lineTemplate, charDelay);
  }
}

(async () => {
  await typeLines(
    document.body,
    ['Type Line 1.', 'Type Line 2.', 'Type Line 3.'],
    '<span data-line-content></span><br>',
    400,
    30,
  );
  await typeLines(
    document.body,
    ['And 2 lines, created by ...', '... default type-settings.'],
  );
})();

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文