Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

Quiero una cadena que aparezca carácter de caracteres con el siguiente código:

function initText()
{
    var textScroller = document.getElementById('textScroller');
    var text = 'Hello how are you?';

    for(c = 0; c < text.length; c++)
    {
        setTimeout('textScroller.innerHTML += text[c]', 1000);
    }
}

window.onload = initText;

No está funcionando .. ¿qué estoy haciendo mal?

¿Fue útil?

Solución

Trate algo como esto:

function initText()
{
    var textScroller = document.getElementById('textScroller');
    var text = 'Hello how are you?';

    var c = 0;
    var interval = setInterval(function() { 
                          textScroller.innerHTML += text[c]; 
                          c++; 
                          if(c >= text.length) clearInterval(interval);
                   }, 1000);

}

Nota añadí clearInterval para detenerlo cuando es necesario.

Otros consejos

En la actualidad, se está definiendo los tiempos de espera 18 y todo será ejecutado ~ a la vez. El segundo problema es, se pasa instrucciones a ejecutar como una cadena. En ese caso, el código no tendrá acceso a todas las variables definidas en initText, porque el código evaluado será ejecutado en el ámbito global.

OMI, esto debería hacer el trabajo

function initText(){
    var textScroller = document.getElementById('textScroller');
    var text = 'Hello how are you?';

    var c = 0;

    (function(){
        textScroller.innerHTML += text.charAt(c++);
        if(text.length > c){
            setTimeout(arguments.callee, 1000);
        }
    })();
}

Aún más genérico que responder por @ Yauhen-Yakimovich:

Uso Timeout:

var repeat = (function () {
    return function repeat(cbWhileNotTrue, period) {
        /// <summary>Continuously repeats callback after a period has passed, until the callback triggers a stop by returning true.  Note each repetition only fires after the callback has completed.  Identifier returned is an object, prematurely stop like `timer = repeat(...); clearTimeout(timer.t);`</summary>

        var timer = {}, fn = function () {
            if (true === cbWhileNotTrue()) {
                return clearTimeout(timer.t); // no more repeat
            }
            timer.t = setTimeout(fn, period || 1000);
        };
        fn(); // engage
        return timer; // and expose stopper object
    };
})();

Uso Interval:

var loop = (function () {
    return function loop(cbWhileNotTrue, period) {
        /// <summary>Continuously performs a callback once every period, until the callback triggers a stop by returning true.  Note that regardless of how long the callback takes, it will be triggered once per period.</summary>

        var timer = setInterval(function () {
            if (true === cbWhileNotTrue()) clearInterval(timer);
        }, period || 1000);
        return timer; // expose stopper
    };
})();

Pequeña diferencia entre los dos se indica en los comentarios - el método repeat sólo se repite después de la devolución de llamada lleva a cabo, por lo que si usted tiene un "lento" devolución de llamada no se ejecutará cada delay ms, pero repite después de cada delay entre ejecuciones, mientras que el método loop se disparará la devolución de llamada cada ms delay. Para detener prematuramente, repeat utiliza un objeto como el identificador devuelto, a fin de utilizar clearTimeout(timer.t) su lugar.

Uso:

Al igual que responder por @ soufiane-hassou:

var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';

var c = 0;
var interval = repeat/* or loop */(function() { 
                      textScroller.innerHTML += text[c]; 
                      c++; 
                      return (c >= text.length);
               }, 1000);

Como se ha mencionado, la parada prematura sería:

/* if repeat */ clearTimeout(interval.t);
/* if loop */   clearInterval(interval);

Prueba esto:

function initText()
{
    var textScroller = document.getElementById('textScroller');
    var text = 'Hello how are you?';

for(c = 0; c < text.length; c++)
{
    setTimeout("textScroller.innerHTML += '" + text[c] + "'", 1000 + c*200);
}
}

window.onload = initText;

Trate de usar un cierre:

function init() {
    var textScroller = document.getElementById('textScroller');
    var text = 'Hello how are you?';
    var c = 0;
    function run() {
        textScroller.innerHTML += text[c++];
        if (c<text.length)
            setTimeout(run, 1000);
    }
    setTimeout(run, 1000);
}
init()

El problema en su código es que el código se pone en la cadena se ejecutará en el contexto global, donde textScroller no está definido (que se define dentro de su función).

Quiero compartir un fragmento (en base a la respuesta por Soufiane Hassou). Se extiende al caso cuando se reemplaza literalmente, un cuerpo de bucle que se repiten a lo largo cierta matriz en un intervalo fijo de tiempo. Básicamente mismo bucle sincrónica pero con "el sueño" pausa (porque Javascript no es un lenguaje de programación sincrónica).

function loop(arr, take, period) {
    period = period || 1000;
    var i = 0;
    var interval = setInterval(function() { 
        take(i, arr[i]);
        if (++i >= arr.length) { clearInterval(interval);}
    }, period);
}

Ejemplo de uso:

loop([1, 2, 3, 4], function(index, elem){
    console.log('arr[' + index + ']: ' + elem);
});

Probado en el Nodo JS. Esperamos que ayuda a alguien.

editar>

la siguiente actualización hace que el código utilizable junto con libs haciendo "prototipos" pesado (como jQuery o prototipo):

function loop(arr, take, period) {
    period = period || 1000;
    var scope = {
        i: 0,
        arr: arr,
        take: take,
    };
    var iterate = (function iterate() {
        if (this.i >= this.arr.length) { clearInterval(this.interval); return}
        take(this.i, this.arr[this.i++]);
    }).bind(scope);
    scope.interval = setInterval(iterate, period);
}

Su ciclo for es establecer un tiempo de espera para cada carácter a la vez, por lo que no aparecerá en la secuencia, pero todos a la vez. Su setTimeout debe incluir el código a otro setTimeout que incluirá el siguiente carácter a visualizar.

Así que algo como esto (no probó esto)

function initText()
{
    var textScroller = document.getElementById('textScroller');
    var text = 'Hello how are you?';    
    setTimeout('nextChar(text)', 1000);
}
function nextChar(text){
    if(text.length > 0){
        textScroller.innerHTML += text[0]; 
        setTimeout('nextChar(text.substring(1))', 1000);
    }
}

Si desea conservar setTimeOut (en lugar de setInterval) y utilizar la función de llamada (en lugar de evaluar bloque de código de llamada setTimeOut), entonces esto podría ser útil:

var b = {
  textScroller: document.getElementById('textScroller'),
  text: "Hello how are you?"
};


function initText() {
  for(c = 0; c < b.text.length; c++) {
    setTimeout("append("+c+")", 1000 + c*200);
  }
}

function append(c) {
  b.textScroller.innerHTML += b.text[c];
}

window.onload = initText;

Con lo anterior se puede pasar un parámetro para añadir la función.

Para pasar varios parámetros el siguiente código hace el truco:

var glo = [];

function initText()
{
  var textScroller = document.getElementById('textScroller');
  var text = "Hello how are you?";
  var timeout_time;
  for(c = 0; c < text.length; c++) {
    glo[glo.length] = {text:text, c:c, textScroller:textScroller};
    timeout_time = 1000 + c * 200;
    setTimeout("append(" + (glo.length - 1) + ")", timeout_time);
  }
}

function append(i)
{
  var obj = glo[i];
  obj.textScroller.innerHTML += obj.text[obj.c];
  obj = null;
  glo[i] = null;
}

window.onload = initText;

Con lo anterior sólo tiene un glo matriz global. En bucle se crean nuevos miembros de la matriz a glo y en función append() referirse a estos miembros utilizando índice que se pasa como parámetro.

PRECAUCIÓN: el segundo ejemplo de código no se entiende como mejor o más adecuada solución a OP: s problema, pero puede beneficiar en otros problemas relativos setTimeout, por ejemplo. cuando alguien quiere hacer una prueba de representación o ejecución, donde se necesitan algunas funcionalidades a llamar después de un cierto retraso. La ventaja de este código es hacer uso de los bucles (muchos codificadores quieren utilizar para bucles) y la posibilidad de utilizar también bucles internos y la capacidad de "enviar" variables locales en su estado de tiempo de bucle a las funciones de tiempo de espera.

Puede que sea mejor para bucle en cascada. Para exemple a desaparecer un div:

div=document.createElement('div');
div.style.opacity=1;
setTimeout(function(){fade(1);},3000);
function fade(op){
    op-=.05;
    if(op>0) setTimeout(function(){div.style.opacity=op;fade(op);},30);
    else document.body.removeChild(div);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top