Печатающийся текст на JS

Рейтинг: -1Ответов: 1Опубликовано: 24.04.2023

Нарыл в интернете код на печатающийся текст в стиле Матрицы:

document.addEventListener('DOMContentLoaded', () => {
  let textBox = document.querySelector('.screen');
  let text = textBox.innerText;
  let newHTML = '';
  let count = 0;
  let j = 0;
  let timeout = 50;


  function initText() {
    newHTML = '';
    for (i = 0; i < text.length; i++) {
      if (text[i] == "\n") {
        newHTML += '<span class="t">' + text[i] + '</span>' + "\n";
      } else {
        newHTML += '<span>' + text[i] + '</span>';
      }

    }
    textBox.innerHTML = newHTML;
    spans = textBox.querySelectorAll('span');
    count = 0;
    j = 0;
  }

  function typing_text() {
    spans[count].classList.add('visible');
    if (spans[count].innerText == ' ' || spans[count].innerHTML == ' ') {
      timeout = Math.floor(Math.random() * Math.floor(1000));
      spans[count].classList.add('cursor');
    } else if (spans[count].innerText == "\r" || spans[count].innerText == "\n") {
      spans[count].classList.add('cursor');
      timeout = 1000;
    } else {
      timeout = 50;
    }
    if (count < text.length - 1) {
      setTimeout(() => {
        spans[count].classList.remove('cursor');
        count++;
        typing_text();
      }, timeout);
    } else {
      setTimeout(() => {
        initText();
        typing_text();
      }, 3000);
    }
  }


  initText();
  typing_text();
});
body {
  background: black;
}

.screen {
  max-width: 500px;
  font: 20px/140% 'Courier New', Courier, Arial;
  padding: 20px;
  background: black;
  color: lime;
  white-space: pre-wrap;
}

.screen span {
  visibility: hidden;
}

.screen span.visible {
  visibility: visible;
}

span.t {
  min-width: 12px;
  max-height: 24px;
  display: inline-block;
}

.screen span.cursor {
  background: lime;
  animation: blinking 1s step-start infinite;
}

@keyframes blinking {
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
<div class="screen">Wake up, Neo...
The Matrix has you...
Follow the white rabbit...
Knock knock, Neo.
</div>

Код есть, но для моих целей он не подходит немного. Мне нужно добавить пару вещей, а именно:

  • Возможность добавления "драматической паузы" путём подставления (допустим) символа "@" в тексте. То есть чтобы символ не отображался, а просто заставлял курсор мигать на одном месте определённый интервал времени (может 0.5 секунды). (Я пытался добавить таймаут по символу в функции typing_text, но когда подставлял, то курсор переставал мигать)

    else if(spans[count].innerText == "@") {
      spans[count].classList.add('cursor');
      spans[count].innerHTML = '';
      timeout = 1000;
    }
    
  • Сделать так, чтобы анимация не воспроизводилась заново. (задать огромное значение таймаута в конце можно, но мне нужно не это. Другого решения найти не смог)

  • (Не обязательно) Объясните пожалуйста, как применять анимацию сразу к нескольким разным блокам. То есть чтобы можно было, например, по нажатию на кнопку вызвать новый блок с текстом, в котором воспроизведётся анимация.

Ответы

▲ 2Принят
  • Возможность добавления "драматической паузы" путём подставления (допустим) символа "@" в тексте:

    1. Добавлем ещё одно условие в список проверок на разные символы:

      else if (spans[count].innerText === "@") {
        spans[count].classList.add('cursor');
        timeout = 10000;
      }
      
    2. Убраем видимость символа @ внутри таймера:

      if (spans[count].innerText === "@") spans[count].classList.remove('visible');
      
  • Сделать так, чтобы анимация не воспроизводилась заново - надо просто убрать последний блок else в ф-ии typing_text:

    else {
      setTimeout(() => {
        initText();
        typing_text();
      }, 3000);
    }
    
  • как применять анимацию сразу к нескольким разным блокам - вместо document.querySelector('.screen'); использовать document.querySelectorAll('.screen');, чтобы достать не один элемент, а коллекцию нужных элементов. Почитайте документацию про querySelector и querySelectorAll

document.addEventListener('DOMContentLoaded', () => {
  document.querySelectorAll('.screen').forEach(textBox => {
    let spans;
    let text = textBox.innerText;
    let newHTML = '';
    let count = 0;
    let j = 0;
    let timeout = 50;


    function initText() {
      newHTML = '';

      for (i = 0; i < text.length; i++) {
        if (text[i] == "\n") {
          newHTML += '<span class="t">' + text[i] + '</span>' + "\n";
        } else {
          newHTML += '<span>' + text[i] + '</span>';
        }

      }
      textBox.innerHTML = newHTML;
      
      spans = textBox.querySelectorAll('span');
      count = 0;
      j = 0;
    }

    function typing_text() {
      spans[count].classList.add('visible');

      if (spans[count].innerText === ' ' || spans[count].innerHTML === ' ') {
        timeout = Math.floor(Math.random() * Math.floor(1000));
        spans[count].classList.add('cursor');
      } else if (spans[count].innerText === "\r" || spans[count].innerText === "\n") {
        spans[count].classList.add('cursor');
        timeout = 1000;
      } else if (spans[count].innerText === "@") {
        spans[count].classList.add('cursor');
        timeout = 10000;
      } else {
        timeout = 50;
      }

      if (count < text.length - 1) {
        setTimeout(() => {
          if (spans[count].innerText === "@") spans[count].classList.remove('visible');
          spans[count].classList.remove('cursor');
          count++;
          typing_text();
        }, timeout);
      }
    }

    initText();
    typing_text();
  });
});
body {
  background: black;
}

.screens {
  display: flex;
  flex-wrap: wrap;
}

.screen {
  max-width: 500px;
  font: 20px/140% 'Courier New', Courier, Arial;
  padding: 20px;
  background: black;
  color: lime;
  white-space: pre-wrap;
}

.screen span {
  visibility: hidden;
}

.screen span.visible {
  visibility: visible;
}

span.t {
  min-width: 12px;
  max-height: 24px;
  display: inline-block;
}

.screen span.cursor {
  background: lime;
  animation: blinking 1s step-start infinite;
}

@keyframes blinking {
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
<div class="screens">
  <div class="screen">Wake up, Neo...@
The Matrix has you...
Follow the white rabbit...
Knock knock, Neo.</div>

  <div class="screen">Wake up, Neo...
The Matrix has you...@
Follow the white rabbit...
Knock knock, Neo.</div>

  <div class="screen">Wake up, Neo...
The Matrix has you...
Follow the white rabbit...@
Knock knock, Neo.</div>

  <div class="screen">Wake up, Neo...
The Matrix has you...
Follow the white rabbit...
Knock knock,@ Neo.</div>
</div>