Pregunta

La función setTimeout siempre parece darme 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 recibe dos argumentos: el elemento a alterar y la altura máxima de los elementos. El propósito de la función es desplegar el elemento, o deslizarse 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 inicialmente se llama a la función. max_height se establece en 20 porque es la altura deseada de los elementos (obtuve este valor de .scrollHeight).

Cuando se realiza la función, quiero que se llame a sí misma 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 de función directamente en la instrucción setTimeout, todavía no funciona.

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

alert(func_call);

Alerta esto:

slide_down([object HTMLParagraphElement], 20);
¿Fue útil?

Solución

Cuando haces esto:

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

estás convirtiendo el elemento en una cadena, por lo que tu tiempo de espera se verá como

slide_down("[Object]", 100);

que obviamente no funcionará.

Lo que debería hacer es crear un cierre: es un poco complicado, pero básicamente crea una función, y las variables locales de la función anterior todavía están disponibles dentro de 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: recomiendo usar 50 como mínimo.

Otros consejos

En primer lugar, esto " En este momento tengo una función que es recursiva (se llama a sí misma a través de setTimeout) " me grita setInterval si no está variando el punto.

En segundo lugar, esto se debe a que la referencia del elemento se pierde en la cadena concat como element.toString () será " [object] " ;. Intente pasar una identificación que pueda volver a encontrar, almacenar una referencia un nivel más arriba, o (como acabo de ver que Matt B señala) el formulario de método expandido.

Una forma más sutil de escribir el método (como extensión de la respuesta de 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 muestra es el uso de argumentos.callee . De esta manera, no romperá su función, si decide cambiarle el nombre. También simplemente configuré la asignación del valor new_height . El problema en el código anterior es que realizó element.clientHeight + factor dos veces, lo cual es poco práctico. No es que tenga ningún efecto notable en su rendimiento en este caso. Pero siempre es bueno evitar calcular las mismas cosas una y otra vez, sino simplemente almacenar el resultado para su uso posterior.

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

Intente cambiar el parámetro de su función para tomar la identificación del elemento y hacer una llamada document.getElementById () dentro de la función.

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

En lugar de:

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

window.setTimeout(func_call, 10);

intente usar la función anónima:

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

@ matt.b: los argumentos que pasan a la llamada setTimeout (de la manera que lo haces) no son compatibles con IE.

Dos cosas:

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

En lugar de:

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

Pruebe esto en su lugar:

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

Update : como mencionó RoBorg, esto puede no funcionar en IE, por lo que es mejor que lo ignore.


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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top