Подтвердить что ты не робот

Пустые пробелы игнорируются свойством InnerText

Я пытаюсь создать функцию (в JavaScript), чтобы написать предложение, написав его буквы, по одному в каждом (например) 300 ms (в теге <p>). Я написал это:

        var text = ["H", "e", "l", "l", "o", " ", "h", "o", "w", " ", "a", "r", "e", "y", "o", "u", "?"]
        function typeText() {
            var i = 0;
            var interval = setInterval(function () {
                var parag = document.getElementById("theParagraph");
                var paragOldText = parag.innerText;
                parag.innerText = paragOldText + text[i];
                i++;
                if (text.length == i)
                    clearInterval(interval);
            }, 200)
        }
<body>
    <p id="theParagraph"></p>
    <button id="typeButton" onclick="typeText()" style="padding:15px">Start typing the sentence</button>
</body>
4b9b3361

Ответ 1

Не используйте презентацию в качестве данных. Сохраняйте текущее содержимое в виде отдельной строки, не вытаскивайте его из DOM. Таким образом, вы не зависите от того, как браузер сохраняет текстовое содержимое элемента.

var text = ["H", "e", "l", "l", "o", " ", "h", "o", "w", " ", "a", "r", "e", "y", "o", "u", "?"]
 
function typeText() {
    var i = 0;
    var paragText = "";
    var interval = setInterval(function () {
        var parag = document.getElementById("theParagraph");
        paragText += text[i];
        parag.innerText = paragText;
        i++;
        if (text.length == i)
            clearInterval(interval);
    }, 200)
}
<body>
    <p id="theParagraph"></p>
    <button id="typeButton" onclick="typeText()" style="padding:15px">Start typing the sentence</button>
</body>

Ответ 2

Как насчет использования textContent?

var text = ["H", "e", "l", "l", "o", " ", "h", "o", "w", " ", "a", "r", "e", " ","y", "o", "u", "?"]

function typeText() {
  var i = 0;
  var interval = setInterval(function() {
    var parag = document.getElementById("theParagraph");
    var paragOldText = parag.textContent;
    parag.textContent = paragOldText + text[i];
    i++;
    if (text.length == i)
      clearInterval(interval);
  }, 200)
}
<body>
  <p id="theParagraph"></p>
  <button id="typeButton" onclick="typeText()" style="padding:15px">Start typing the sentence</button>
</body>

Ответ 3

Другие ответы касаются проблем с вашим кодом, но я хотел бы рассмотреть проблемы с вашим планом.

  • Вы действительно хотите определить массив символов? Длинные предложения будут адом. А что, если вы хотите переменный текст? Используйте это вместо:

    var input = "Hello how are you?";
    var text = input.split(""); // split into array of characters
    
  • Говоря о более длинных предложениях, ваша "пишущая машинка" заполнит текущую строку, поймет, что у нее нет места, а затем нажмите последнее слово до следующей строки, чтобы закончить его. Это неплохой взгляд! Вы можете обойти это с помощью умного трюка:

    <p><span id="visible_text">Hello how a</span><span id="remaining_text">re you?</span></p>
    <style>#remaining_text {visibility:hidden}</style>
    

    Мало того, что эта обработка дескрипторов слов будет очень приятной, она также "зарезервирует" необходимое пространство раньше времени, так что вы не закончите тем, что подталкиваете содержимое ниже пишущей машинки дальше страницы, когда появятся новые линии.

    Вы можете легко достичь этого эффекта, посчитав позицию персонажа, на котором вы находитесь, а затем разделите строку input на две части при этом смещении. Поместите первый кусок в первый <span>, остальные во втором, а вы золотой.

Источник: Я использую эту технику в своем стиле "RPC cutscene". На самом деле это более продвинутая версия, так как моя также поддерживает HTML, а не просто текст!

Ответ 4

Вам нужно ввести пробел с помощью &nbsp; и использовать innerHTML вместо innerText

var paragOldText = parag.innerHTML;
parag.innerHTML = paragOldText + ( text[i].trim().length ? text[i] : "&nbsp;" ) ;

Edit

&nbsp; не требуется с innerHTML

var paragOldText = parag.innerHTML;
parag.innerHTML = paragOldText + text[i] ;

Demo

var text = ["H", "e", "l", "l", "o", " ", "h", "o", "w", " ", "a", "r", "e", "y", "o", "u", "?"]

function typeText() {
  var i = 0;
  var interval = setInterval(function() {
    var parag = document.getElementById("theParagraph");
    var paragOldText = parag.innerHTML;
    parag.innerHTML = paragOldText + text[i];
    i++;
    if (text.length == i)
      clearInterval(interval);
  }, 200)
}
<body>
  <p id="theParagraph"></p>
  <button id="typeButton" onclick="typeText()" style="padding:15px">Start typing the sentence</button>
</body>

Ответ 5

Я изменил ваш код, чтобы показать, как вы можете использовать метод среза для более короткого и элегантного кода.

var text = "Hello how are you?"
function typeText() {
var i = 0;
var parag = document.getElementById("theParagraph");
var interval = setInterval(function () {
    i++;
    parag.innerText = text.slice(0, i);
    if (i == text.length)
        clearInterval(interval);
    }, 200)
}
<body>
    <p id="theParagraph"></p>
    <button id="typeButton" onclick="typeText()" style="padding:15px">Start typing the sentence</button>
</body>

Ответ 6

Эта проблема является отличным кандидатом на шаблон MVC. Я обсуждаю эту точную проблему в blog. Я представил MVC для этой проблемы ниже. (Пожалуйста, извините за бесстыдную саморекламу.)

const Model = function(){
   const self = this;
   self.index = 0;
   self.text = ["H", "e", "l", "l", "o", " ", "h", "o", "w", " ", "a", "r", "e", " ", "y", "o", "u", "?"];
   self.textString = "",
   self.accumulate = function(){
     const length = self.text.length;
     self.textString = self.textString + self.text[self.index];
     self.index = ++self.index % length;
   }
 }
  const Controller = function(model, elem, milsec){
   const self = this;
   self.elem = elem;
   self.start = function(){
     const interval = setInterval( function(){
      if(model.index===model.text.length-1){
       clearInterval(interval);
     }
       model.accumulate();
       self.elem.innerText = model.textString;   
     }, milsec);
   }
 }
 
 const typeText = function(){
   const model = new Model();
   const theParagraph = document.getElementById('theParagraph');
   const controller = new Controller(model, theParagraph, 200);
   controller.start();
 }
<body>
    <p id="theParagraph"></p>
    <button id="typeButton" onclick="typeText()" style="padding:15px">Start typing the sentence</button>

<p>
  I invite you to go to my <a target='_top' href="#" onclick="location.href='https://www.monilito.com/blog/Never-Use-Presentational-Structures-to-Store-State'; return false;">blog article</a> for an interesting take on this problem.
</p>
</body>