Quiero simular una función de autocompletar. Una oración debe completarse con palabras de una lista. Estas palabras deben mostrarse carácter por carácter al final de la oración.
Este es el HTML:
<p>We can help you with<span id="complete"></span></p>Esto es parte del JS:
let words = ["design", "frontend", "backend"]; let output = document.getElementById("complete");Primero probé esto:
words.forEach((e) => { for (i = 0; i < e.length; i++) { setTimeout(() => { console.log(e[i]); }, 500); } });consola registrada:
Creo que es porque el iterador avanza antes de setTimeout.
Así que probé un ciclo while como este:
words.forEach((e) => { let i = 0; while (i <= e.length) { setTimeout(() => { console.log(e[i]); }, 600); i++; } });Tengo esto:
No tengo idea de cómo colocar carácter por carácter, de modo que sumen la palabra como: d; Delaware; des; Desi; diseño; diseño con una especie de retraso entre cada carácter.
(Para colocar las palabras char por char en el DOM, no usaría el registro de la consola, sino complete.innerHTML += variableForWordinList[index for char])
Gracias
Creo que es porque el iterador avanza antes de setTimeout.
Si agrega un console.log(i) al bucle, verá un valor inesperado, por lo que sus suposiciones parecen correctas.
Dado que probablemente queremos mostrar las 3 palabras una detrás de la otra, no combinadas, necesitaremos otra forma de 'esperar' después de que se haya 'escrito' la primera palabra
Existen muchas bibliotecas, como TypewriterJs o uno de los complementos de jQuery , pero para aprender, intentemos crear una nosotros mismos.
let words = ["design", "frontend", "backend"]; let output = document.getElementById("complete"); const s = ms => new Promise(resolve => setTimeout(resolve, ms)); async function showWord(w) { output.innerHTML = ''; for (let i = 0; i < w.length; i++) { await s(150); output.innerHTML += w[i]; } await s(500); } words.reduce((c, w) => c.then(showWord.bind(null, w)) , showWord(words.shift())); <p>We can help you with <span id="complete"></span></p> La función s usa Promises para 'esperar' algunos milisegundos.
Luego definimos una función async que 'escribirá' nuestra palabra y la retrasará cuando sea necesario.
Usando reduce podemos recorrer la matriz de palabras, usando shift para eliminarla de la matriz
setTimeout es asíncrono. Entonces, cuando ejecuta la función, el valor que está registrando ya ha cambiado.
Lo que estás tratando de lograr es una especie de efecto de máquina de escribir. Se puede lograr usando una combinación de setInterval y setTimeout .
let words = ["design", "frontend", "backend"]; let output = document.getElementById("complete"); let idx = 0; let str = ""; function typeWrite() { if (idx >= words.length) idx = 0; let word = words[idx]; let charInd = 0; let interval = setInterval(() => { if (charInd >= word.length) { clearInterval(interval); setTimeout(() => { idx++; str = ""; typeWrite(); }, 1000); // <- Wait for 1 sec before printing next word } str += word.charAt(charInd); output.innerHTML = str; charInd++; }, 100); // <- Delay between each character } typeWrite(); <p>We can help you with <span id="complete"></span></p>Lo uso para la subcadena de casos. Como eso:
words = ['Hello World']; function showC(words) { let str = words.join() for(let i = 0; i <= str.length; i++) { setTimeout(() => { console.log(str.substring(0, i)); }, 500*i); } } showC(words)