首页 > 解决方案 > 如何遍历任何字母数组并通过 DOM 中的每个字母进行动画处理

问题描述

我正在尝试创建打字机效果动画,因此当我在输入框中键入时,会显示一条新消息并进行动画处理。

我尝试让一个全局 char 变量遍历数组的每个元素,但是当我传递另一个其他字母数组时,在输入框中输入文本后,h1 不会被覆盖。

这是我的尝试

    // wrap each letter in output in a span 
    function createInduvidualLetterSpans(letterArr) {
    if (textEl.innerHTML) {
        textEl.innerHTML = ''
    }

    for (const letter of letterArr) {
        const letterEl = document.createElement('span')
        letterEl.textContent = letter
        textEl.appendChild(letterEl)
    }
    return textEl
    }

    // animate each letter
    let char = 0

    function displayChars() {
    const span = textEl.querySelectorAll('span')[char]
    span.classList.add('load')
    char++
    if (char == textArr.length) {
        complete()
        return
    }
    }

    function complete() {
    clearInterval(timer)
    timer = null
    }

    createInduvidualLetterSpans(textArr)
    let timer = setInterval(displayChars, 10)

我的下一个尝试是尝试迭代器和闭包。我刚刚阅读了这些想法,并立即认为这对他们来说是一个完美的用例。但是,我让文本向前动画,但我得到了一个

span is unidentified 错误,我不知道为什么。

//turn text into an array of letters
const textEl = document.querySelector('h1')

const textArr = textEl.textContent.split('')
const explore = 'Your lack of desire has lead you towards a life of bordeom and dread. [[GAME OVER]]'.split('')

const userInput = document.getElementById('user-input')
textEl.textContent = ''

// iterator fn
function iterator(arr) {
    let count = 0
    
    const inner = {
        next: function () {
            const el = arr[count]
            count++
            arr[count] == undefined ? done = true : done = false
            return {
                value: el,
                done
            }
        },
        createSpan: function (letterArr) {
            textEl.textContent = ''
            for (const letter of letterArr) {
                const letterEl = document.createElement('span')
                letterEl.textContent = letter
                textEl.appendChild(letterEl)
            }
        },
        animateEachLetter: function () {
            const span = textEl.querySelectorAll('span')[count]
            span.classList.add('load')
            count++
            arr[count] == undefined ? done = true : done = false
        }

    }
    return inner
}

const it = iterator(explore);
it.createSpan(explore)

const exploreRoom = () => {
    it.createSpan(explore)
}
exploreRoom()

setInterval(it.animateEachLetter, 10)
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  font-size: 62.5%;
}

body {
  max-width: 100%;
}

span {
  opacity: 0;
}

span.load {
  opacity: 1;
}
<div class="grid">
  <h1>You wake, confused and disoriented. Something just does not feel quite right. You reach over to the night stand, find a pair of glasses, put them on (even though you do not wear glasses and stand up. Do you explore the room or go back to bed?</h1>

  <form id="user-input">
    <input id="user-text" class="input" type="text" name="text" autofocus>
  </form>

</div>

标签: javascripthtmldomiteratorclosures

解决方案


setInterval(it.animateEachLetter, 10)

    animateEachLetter: function () {
        const span = textEl.querySelectorAll('span')[count]
        span.classList.add('load')
        count++
        arr[count] == undefined ? done = true : done = false
    }

您正在调用animateEachLetter并尝试查找span,更改其类并增加计数。听起来您只需要先检查是否存在这样的跨度 - 如果不存在,请清除间隔。迭代器协议使事情变得比他们需要的更加混乱,您可以考虑完全删除它。

此外,您实际上是为单个animateEachLetter字母设置动画,而不是每个字母。考虑有一个方法可以实际为每个字母设置动画,该方法调用不同的方法(在间隔中运行的方法)为一个字母设置动画:animateEachLetter

const textEl = document.querySelector('h1');
const textArr = textEl.textContent.split('');
const explore = 'Your lack of desire has lead you towards a life of bordeom and dread. [[GAME OVER]]'.split('');
const userInput = document.getElementById('user-input');

function makeAnimator(arr) {
  let count = 0;

  return {
    createSpan: function(letterArr) {
      textEl.textContent = '';
      for (const letter of letterArr) {
        const letterEl = document.createElement('span');
        letterEl.textContent = letter;
        textEl.appendChild(letterEl);
      }
    },
    animateEachLetter(ms) {
      this.interval = setInterval(() => this.animateOneLetter(), ms);
    },
    animateOneLetter() {
      const span = textEl.querySelectorAll('span')[count];
      if (!span) {
        clearInterval(this.interval);
        return;
      }
      span.classList.add('load')
      count++
      arr[count] == undefined ? done = true : done = false
    }

  };
}

const animator = makeAnimator(explore);
animator.createSpan(explore)
animator.animateEachLetter(20);
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  font-size: 62.5%;
}

body {
  max-width: 100%;
}

span {
  opacity: 0;
}

span.load {
  opacity: 1;
}
<div class="grid">
  <h1>You wake, confused and disoriented. Something just does not feel quite right. You reach over to the night stand, find a pair of glasses, put them on (even though you do not wear glasses and stand up. Do you explore the room or go back to bed?</h1>

  <form id="user-input">
    <input id="user-text" class="input" type="text" name="text" autofocus>
  </form>

</div>


推荐阅读