一旦前一个循环,如何遍历数组?

时间:2020-04-28 08:58:24

标签: javascript arrays string setinterval

我正在制作装饰性文字,该文字会打印出一个字母,直到形成一个单词,然后逐个字符删除该单词以编写一个新单词。我把所有的字符串都变成一个数组,而且我知道我可能需要使用.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);

3 个答案:

答案 0 :(得分:1)

  • 将skillData对象更改为数组
  • 使用currentIndex变量保留当前单词的记录
  • 创建一个“完成”布尔值,以在数组完成迭代后停止执行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);

答案 1 :(得分:0)

您可以尝试以下操作:

  • 使用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);

答案 2 :(得分:0)

每打印一个单词(在您的情况下删除一个单词),您就需要知道一个条件。由于单词的长度不同,建议您使用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>