如何在前一个数组循环后循环遍历数组?

How to loop through an array once the previous are has looped?

我正在制作一个装饰性文本,打印一个字母直到它形成一个单词,然后逐个字符删除该单词以写一个新单词。我将所有的字符串都变成了一个数组,我知道我可能需要使用 .length、.slice() 和 .join。但让我难过的一件事是,一旦前一个数组循环结束,我该如何启动下一个数组?

const skillData = {
  js: [..."javascript"],
  ts: [..."typescript"],
  reactJS: [..."reactJS"],
  html: [..."HTML5"],
  css: [..."CSS3"],
  reactNative: [..."React Native"],
  node: [..."NodeJS"],
  mongo: [..."MongoDB"],
  phaser: [..."Phaser 3"],
  py: [..."Python"],
};

let arrayClimber = 0;
const moveSkill = () => {
  if (arrayClimber < skillData.js.length) {
    arrayClimber += 1;
    console.log("going up " + arrayClimber);
  }

  //Needs to start going down then one it reaches zero it should change to the typescript, reactJS, etc arrays
  console.log(skillData.js.slice(0, arrayClimber).join(""));

};

setInterval(moveSkill, 150);

您可以尝试这样的操作:

  • 使用Object.keysfor...in
  • 循环对象的键
  • 获取当前技能。
  • 循环当前技能和打印值。您可以使用 .reduce 或正常的 for 循环
    • 创建一个变量来保存要打印的字符串。由于它需要保存先前迭代的值,因此需要在此循环之外定义它。
    • 每次迭代,您将当前字符添加到它并打印值。
    • 在这个循环的最后,你可以截断它或者在循环之前,你可以将它初始化为默认的空。

注意: 为了防止控制台泛滥,我使用了 setTimeout 而不是 setInterval

此外,SO 对集成控制台中显示的值有限制。为了获得正确的结果,请检查实际浏览器的控制台

const skillData = {
  js: [..."javascript"],
  ts: [..."typescript"],
  reactJS: [..."reactJS"],
  html: [..."HTML5"],
  css: [..."CSS3"],
  reactNative: [..."React Native"],
  node: [..."NodeJS"],
  mongo: [..."MongoDB"],
  phaser: [..."Phaser 3"],
  py: [..."Python"],
};

const moveSkill = () => {
  for (const key in skillData) {
    const skill = skillData[key];
    
    skill.reduce((str, char) => {
      str += char;
      console.log(str);
      return str;
    }, '')
  }

};

setTimeout(moveSkill, 150);

  • 将 skillData 对象更改为数组
  • 使用 currentIndex 变量记录当前单词
  • 创建一个 'finished' 布尔值以在数组完成迭代时停止执行 setInterval。

const skillData = [
  [..."javascript"],
  [..."typescript"],
  [..."reactJS"],
  [..."HTML5"],
  [..."CSS3"],
  [..."React Native"],
  [..."NodeJS"],
  [..."MongoDB"],
  [..."Phaser 3"],
  [..."Python"],
];

let arrayClimber = 0;
let currentIndex = 0;
let finished = false;
const moveSkill = () => {
  if (arrayClimber < skillData[currentIndex].length) {
    arrayClimber += 1;
    console.log("going up " + arrayClimber);
  } else {
    currentIndex++;
    arrayClimber = 0;
  }
  
  if (skillData.length == currentIndex) {
    finished = true;
    return;
  }

  //Needs to start going down then one it reaches zero it should change to the typescript, reactJS, etc arrays
  console.log(skillData[currentIndex].slice(0, arrayClimber).join(""));

};

setInterval(() => {
  if (!finished)
    moveSkill();
}, 150);

只要打印了一个单词(并在您的情况下将其删除),您就需要知道一个条件。由于单词的长度不同我建议你使用promises。有了promises,你可以检查一个词的条件是否已经完全打印出来,然后履行promise。

这使您能够在开始下一个单词之前动态等待每个单词打印完毕。通过迭代器协议的组合,您可以遍历每个承诺并等待它完成,然后再开始下一个单词。

下面的示例使用 generator function 创建这样一个可迭代对象,它为需要打印的每个单词产生一个承诺。当循环此对象时,您打印每个单词,等待它完成,然后继续列表中的下一个单词。

这种方法的一个优点是您可以轻松控制每个单词的时间,并且代码是非阻塞的。所以其他脚本将 运行 而不必等待这个脚本结束。

const wordElement = document.getElementById('word');

const skillData = {
  js: [..."javascript"],
  ts: [..."typescript"],
  reactJS: [..."reactJS"],
  html: [..."HTML5"],
  css: [..."CSS3"],
  reactNative: [..."React Native"],
  node: [..."NodeJS"],
  mongo: [..."MongoDB"],
  phaser: [..."Phaser 3"],
  py: [..."Python"],
};

const printWord = (word, speed) => new Promise(resolve => {
  let index = 1;
  let wordLength = word.length;
  let interval = setInterval(() => {
    if (index <= wordLength) {
      let partOfWord = word.slice(0, index).join('');
      requestAnimationFrame(() => {
        wordElement.textContent = partOfWord;
      });
      index++
    } else {
      clearInterval(interval);
      resolve(word);
    }
  }, speed);
});

async function* wordPrinter(data) {
  for (const word of Object.values(data)) {
    yield printWord(word, 100);
  }
}

async function printWords() {
  for await (const word of wordPrinter(skillData)) {
    console.log('Word printed:', word.join(''));
  }
  return 'Done printing';
}

printWords().then(console.log);
<p id="word"></p>