Arad
Estoy tratando de escribir una función (en JavaScript) que escribiría una oración en un <p>
etiqueta escribiendo sus letras una por una con una pausa de 300 ms entre cada letra, por ejemplo. He escrito lo siguiente:
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>
Como puede ver, hay algunos caracteres ” ” (espacio vacío) en la matriz; el problema es que no escribe esos espacios vacíos, por lo que la oración quedaría así: “Hola como eres”. ¿Cómo puedo solucionar esto?
No utilice la presentación como datos. Almacene el contenido actual como una cadena separada, no lo extraiga del DOM. De esta manera, no depende de cómo el navegador almacena el contenido de texto del elemento.
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>
Como nota al margen, lo mismo podría simplificarse mucho:
var text = "Hello how are you?";
function typeText() {
var i = 0;
var interval = setInterval(function () {
var parag = document.getElementById("theParagraph");
parag.innerText = text.substr(0, i);
if (text.length == i)
clearInterval(interval);
i++;
}, 200)
}
<body>
<p id="theParagraph"></p>
<button id="typeButton" onclick="typeText()" style="padding:15px">Start typing the sentence</button>
</body>
-
Si bien las otras respuestas son ciertamente correctas y contienen información útil, esta respuesta mencionó algo importante que ni siquiera se me ocurrió. gj
– Juan Wu
12 de diciembre de 2017 a las 10:31
Gerardo Furtado
¿Qué pasa con el uso 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>
También puedes usar innerHTML
:
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>
innerText
fue presentado por IE y, como todos sabemos, nada bueno viene de IE. Bromas aparte, esta es una buena explicación al respecto: “El pobre e incomprendido texto interior”.
-
Hoy en día, todo lo que se escribe sobre la compatibilidad con los navegadores envejece bastante rápido, también FF se ha adaptado
innerText
últimamente.– Teemu
12 de diciembre de 2017 a las 10:51
-
¡Gracias! esto me ha ayudado. pero seria mejor que le digas la causa
– Arad
12 de diciembre de 2017 a las 12:14
-
@Teemu Más exactamente, ha sido adoptado por WHATWG últimamente.
– Beto
13 de diciembre de 2017 a las 2:16
Las otras respuestas abordan los problemas con su código, pero me gustaría abordar los problemas con todo su plan.
-
¿Realmente quieres definir una serie de personajes? Las oraciones largas van a ser un infierno. ¿Y si quieres texto variable? Usa esto en su lugar:
var input = "Hello how are you?"; var text = input.split(""); // split into array of characters
-
Hablando de oraciones más largas, su “máquina de escribir” completará la línea actual, se dará cuenta de que no tiene espacio y luego bajará la última palabra a la siguiente línea para terminarla. ¡Esto no es un buen aspecto! Puedes evitar esto con un truco inteligente:
<p><span id="visible_text">Hello how a</span><span id="remaining_text">re you?</span></p> <style>#remaining_text {visibility:hidden}</style>
Esto no solo manejará muy bien el ajuste de palabras, sino que también “reservará” el espacio necesario con anticipación para que no termine empujando el contenido debajo de la máquina de escribir más abajo en la página a medida que surgen nuevas líneas.
Puede lograr fácilmente este efecto contando en qué posición de personaje se encuentra y luego dividiendo el
input
cadena en dos piezas en ese desplazamiento. Pon la primera pieza en la primera.<span>
el resto en el segundo, y estás dorado.
Fuente: uso esta técnica en mi código de estilo “RPG cutscene”. En realidad, una versión más avanzada, ya que la mía también es compatible con HTML en lugar de solo texto sin formato.
gurvinder372
Necesitas introducir el espacio usando
y use innerHTML
en vez de innerText
var paragOldText = parag.innerHTML;
parag.innerHTML = paragOldText + ( text[i].trim().length ? text[i] : " " ) ;
Editar
no se requiere con innerHTML
var paragOldText = parag.innerHTML;
parag.innerHTML = paragOldText + text[i] ;
Manifestación
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>
He modificado tu código para mostrar cómo puedes usar el método de corte para un código más corto y elegante.
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>
Zack Plauche
Respuesta corta: Usar textContent
atributo en lugar de innerText
atributo y podrá agregar espacios.
p.ej
var text = ["H", "e", "l", "l", "o", " ", "h", "o", "w", " ", "a", "r", "e", " ", "y", "o", "u", "?"] // Added missing space after "are"
function typeText() {
var i = 0;
var interval = setInterval(function() {
var parag = document.getElementById("theParagraph");
var paragOldText = parag.textContent; // Replaced "parag.innerText" with "parag.textContent"
parag.textContent = paragOldText + text[i]; // Did it again.
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>
Además, tenga en cuenta que Konrad Rudolph y bergi respondieron el por qué en los comentarios directamente sobre la pregunta.
monilito castro
Este problema es un gran candidato para un patrón MVC. Discuto este problema exacto en mi Blog. He proporcionado un MVC para este problema a continuación. (Disculpe la desvergonzada autopromoción).
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="https://www.monilito.com/blog/Never-Use-Presentational-Structures-to-Store-State">blog article</a> for an interesting take on this problem.
</p>
</body>
-
Esta solución complica innecesariamente el código sin valor añadido, tratando de encajar una clavija cuadrada grande en un pequeño agujero redondo.
– d4nyll
10 jun 2021 a las 20:43
Como ninguna de las otras respuestas explica por qué tu código no funciona: en pocas palabras, es porque
innerText
representa el texto renderizado en una página, lo que significa aplicar el elementowhite-space
normas. El efecto en su caso es que se eliminan los espacios en blanco circundantes.– Konrad Rodolfo
12 dic 2017 a las 10:40
Eche un vistazo a la diferencia entre el contenido del texto y el texto interno y posiblemente también esto
– Bergi
12 de diciembre de 2017 a las 14:36
Lee el comentario de Bergi^
– Zack Plauché
24 de junio de 2020 a las 6:05