2008-12-04 33 views
5

La función setTimeout siempre me da problemas. En este momento tengo una función que es recursiva (se llama a sí misma a través de setTimeout) y cambia la altura de los elementos.La función setTimeout de Javascript no llama a

La función se envía dos argumentos: el elemento que se va a modificar y que los elementos de altura máxima. El propósito de la función es desplegar el elemento, o "deslizar hacia abajo" a un ritmo constante. Soy consciente de que probablemente podría resolver este problema con jQuery, pero estoy probando mi propia función.

function slide_down(element, max_height) 
{ 
    if(element.clientHeight < max_height) 
    { 
     var factor = 10; 
     var new_height = (element.clientHeight + factor >= max_height) ? max_height : (element.clientHeight + factor); 
     element.style.height = new_height + 'px'; 

     var func_call = 'slide_down(' + element + ', ' + max_height + ');'; 
     window.setTimeout(func_call, 10); 
    } 
} 

He probado los argumentos cuando se llama inicialmente a la función. max_height está establecido en 20 porque es la altura deseada de los elementos (obtuve este valor de .scrollHeight).

Cuando la función está lista, quiero que se llame solo hasta que max_height sea la altura del elemento. Lo hago con esta llamada setTimeout:

var func_call = 'slide_down(' + element + ', ' + max_height + ');'; 
window.setTimeout(func_call, 10); 

Y no está funcionando. Esto funciona:

var func_call = 'alert(1);'; 
window.setTimeout(func_call, 10); 

También he intentado poner la llamada a la función directamente en la declaración setTimeout, sigue sin funcionar.

Tenga en cuenta que la altura del elemento SI cambia la primera iteración, la función nunca se llama a sí misma. Entonces la variable del elemento está configurada correctamente, y utilicé alert() para mostrar el max_height que también es correcto.

alert(func_call); 

Alertas esto:

slide_down([object HTMLParagraphElement], 20); 

Respuesta

19

Al hacer esto:

var func_call = 'slide_down(' + element + ', ' + max_height + ');'; 

que estés elemento de conversión de una cadena, por lo que su tiempo de espera se verá como

slide_down("[Object]", 100); 

que obviamente no va a funcionar.

Lo que debe hacer es crear un cierre, es un poco complicado, pero básicamente crea una función, y la variable local de la función anterior todavía está disponible en la nueva función.

function slide_down(element, max_height) 
{ 
    if(element.clientHeight < max_height) 
    { 
     var factor = 10; 
     var new_height = (element.clientHeight + factor >= max_height) ? max_height : (element.clientHeight + factor); 
     element.style.height = new_height + 'px'; 

     var func = function() 
     { 
      slide_down(element, max_height); 
     } 

     window.setTimeout(func, 10); 
    } 
} 

También 10 es un poco corto para un tiempo de espera - Yo recomendaría usar 50 como mínimo.

+0

Gracias. Lo estaba buscando. – HOT

1

tuve una experiencia similar. Cuando pasa elemento la próxima vez, se convierte en una cadena en la llamada a función, de modo que cuando la función se ejecuta, trata de encontrar un elemento llamado [object] .string o algo, en lugar de lo que pretendía.

Intente cambiar su parámetro de función para tomar la identificación del elemento y realizar una llamada a document.getElementById() en primer lugar dentro de la función.

0

dos cosas:

1. Hay una forma alternativa de llamar setTimeout() en el que se pasa a la función y los parámetros, en lugar de una cadena de ejecutar. De hecho, the Gecko DOM manual states no se recomienda su versión de llamada setTimeout().

En lugar de:

var func_call = 'slide_down(' + element + ', ' + max_height + ');'; 
window.setTimeout(func_call, 10); 

Tal vez puedas probar:

window.setTimeout(slide_down, 10, element, max_height); 

actualización: como se ha mencionado RoBorg, esto puede no funcionar en IE, por lo que también podría ignorarlo.


2. Tengo la sensación de que llamar setTimeout() desde una función que se llamó a sí mismo por setTimeout() no está permitido o no funciona bien. Supongo que está encadenando las llamadas de esta manera porque quiere que el código se ejecute repetidamente. Si es así, para eso sirve window.setInterval().

+0

¿Es incorrecto el manual de Mozilla DOM ...? –

+0

Hmm Supongo que nunca encontré esa sintaxis porque "Tenga en cuenta que pasar parámetros adicionales a la función en la primera sintaxis no funciona en Internet Explorer". Tu primer enlace apareció 404 antes, entonces o editaste o fue un error técnico. -1 eliminado – Greg

+0

He solucionado un problema con los enlaces, el https no estaba formateado correctamente. Gracias. –

3

En primer lugar, este "Ahora mismo tengo una función que es recursivo (llama a sí misma a través setTimeout)" grita setInterval a mí si usted no está variando el periodo.

En segundo lugar, esto se debe a que la referencia del elemento se pierde en la cadena concat como elemento.toString() será "[objeto]". Trate de pasar una identificación que puede volver a encontrar, almacenar una referencia de un nivel arriba, o (como acabo de ver mate b señalar) la forma de método ampliado.

1

El problema con su código es que no pasa el parámetro del elemento.

En lugar de:

 
var func_call = 'slide_down(' + element + ', ' + max_height + ');'; 

window.setTimeout(func_call, 10); 

tratar de usar función anónima:

 

window.setTimeout(function() { 
    slide_down(element, max_height) 
}, 10); 

@ matt.b: argumentos que pasan en la llamada setTimeout (la forma en que lo hacen) no se admite en el IE.

2

Una forma más sutil de escribir el método (como la extensión a la respuesta Gregs):

function slide_down(element, max_height) 
{ 
    if(element.clientHeight < max_height) 
    { return; } 

    var factor = 10, 
     new_height = element.clientHeight + factor, 
     f = arguments.callee; 

    if(new_height > max_height) 
    { new_height = max_height; } 

    element.style.height = new_height + 'px'; 

    window.setTimeout(function() { f(element, max_height); }, 10); 
} 

La verdadera ventaja de este código de ejemplo es el uso de arguments.callee. De esta forma, no interrumpirá su función, en caso de que decida cambiarle el nombre. También simplifiqué la asignación de valores new_height. El problema en el código anterior es que realizó element.clientHeight + factor dos veces, lo cual es un poco antipático. No es que tenga ningún efecto notorio en su desempeño en este caso. Pero siempre es bueno evitar calcular las mismas cosas una y otra vez, pero simplemente almacene el resultado para usarlo más adelante.

Cuestiones relacionadas