1

The question I have is how to I get multiple instances of a function to run. Here is my function below - A simple fade function. Problem I'm having is that when it is called a second time it abandons the first call. So if a user clicks on a button it will display a message which fades.

If the user clicks on another button the previous fading message just stops at the current opacity level.

?

What is the stopping mechanism? Where did the previous function go?

The function

function newEffects(element, direction, max_time ) 
{
    newEffects.arrayHold = [];
    newEffects.arrayHold[element.id] = 0;

    function next() 
    {
        newEffects.arrayHold[element.id] += 10;
        if ( direction === 'up' )
        {
            element.style.opacity = newEffects.arrayHold[element.id] / max_time;
        }
        else if ( direction === 'down' )
        {
            element.style.opacity = ( max_time - newEffects.arrayHold[element.id] ) / max_time;
        }
        if ( newEffects.arrayHold[element.id] <= max_time ) 
        {
            setTimeout( next, 10 );
        }
    }
    next();
    return true;
};

The Call

newEffects(this.element, 'down', 4000 ); 

Old Object

/**
 *    Effects - causes all elements that are fading to sync. to same opacity level as they share the same elapsed time.
 */

var Effects = function( element ) 
{
    this.element = element;
};

Effects.prototype.fade = function( direction, max_time ) 
{
    Effects.elapsed = 0;
    var persist_element = this.element;
    function next() 
    {
        Effects.elapsed += 10;
        if ( direction === 'up' )
        {
            persist_element.style.opacity = Effects.elapsed / max_time;
        }
        else if ( direction === 'down' )
        {
            persist_element.style.opacity = ( max_time - Effects.elapsed ) / max_time;
        }
        if ( Effects.elapsed <= max_time ) 
    {
            setTimeout( next, 10 );
        }
    }
    next();
    return true;
};
4

3 に答える 3

1

It looks like you are calling next() recursively. I'm surprised your code isn't crashing.

于 2012-04-07T17:26:50.507 に答える
1

Try this

function newEffects(element, direction, max_time ) 
{
    var mt=max_time;
    var dir=direction; 
    var el=document.getElementById(element);
    var newEffects={};
    newEffects.arrayHold = [];
    newEffects.arrayHold[el.id] = 0;

    function next() 
    {
        newEffects.arrayHold[el.id] += 10;
        if ( dir === 'up' )
        {
            el.style.opacity = newEffects.arrayHold[el.id] / mt;
        }
        else if ( dir === 'down' )
        {
            el.style.opacity = ( mt - newEffects.arrayHold[el.id] ) / mt;
        }
        if ( newEffects.arrayHold[el.id] <= mt ) 
        {
            setTimeout( next, 10 );
        }
    } next();
};

An example is here.

Declare every variable using var keyword inside the parent function to keep separate instance of each items, this is how clouser works.

于 2012-04-07T17:52:41.643 に答える
1

Consider this code:

function foo() {
    foo.bar = 5;
    alert(foo.bar); // alerts 5
}
foo();
alert(foo.bar); // alerts 5 instead of undefined!

Foo is an object that has properties, but can also be called as a function. Any properties that are set will persist, even outside the function call. (In fact, this is a way to make a Javascript pseudo-class, which is useful for its own purposes.)

What you can do instead is return new instances of this "class", in one of the two following ways:

function fadeEffect(element) {
    this.element = element;
    this.fadeTimeLeft = 1000;
    this.fade = function() {
        this.fadeElement.style.opacity -= .01; // Replace with working
                                               // opacity decreaser.
        this.fadeTimeLeft -= 1;
        if (this.fadeTimeLeft > 0) {
            setTimeout(this.fade, 10);
        }
    }
}

signInButtonFade = new fadeEffect(document.getElementById("signinfade"));

Or in Javascript's object-literal notation, which you may know better as JSON:

function fadeEffect(element) {
    return {
        "fadeElement": element,
        "fadeTimeLeft": 1000,
        "fade": function() {
            this.fadeElement.style.opacity -= .01; // Replace with working
                                                   // opacity decreaser.
            this.fadeTimeLeft -= 1;
            if (this.fadeTimeLeft > 0) {
                setTimeout(this.fade, 10);
            }
        },
        "init": function() {
            // When using this format, no code is executed automatically,
            // so we have a "constructor" that we execute manually when
            // making the object.
            this.fade();
        }
    }
}

signInButtonFade = generateFade();
signInButtonFade.init();

(Obviously, the actual opacity decreasing is not functional.)

You can also store each of these fade effects in an array, and then check to see if there are any previous fade effects that are being applied to an element. If there are, then either you can stop that fade or hijack it into fading the other way, or something else entirely.

fadeArray = new Array();
fadeArray.push(new fadeEffect(document.getElementById("fadeElement"));

// Do other adding fade stuff, etc...

// Now we add a new fade effect. This could easily be put into a function:
fadeEffectAlreadyExists = false;
for (i in fadeArray) {
    if (i.element == document.getElementById("fadeElement2")) {
        fadeEffectAlreadyExists = true;
        break;
    }
}
if (!fadeEffectAlreadyExists) {
    fadeArray.push(new fadeEffect(document.getElementById("fadeElement2")));
}

While this is fine and all (and in my opinion, the correct way to do it), you can probably keep your existing function by replacing each instance of "newEffects" in the function body with "this", and then use fade = new newEffects(element, direction, max_time); since it already shares quite a bit in common with the first approach.

于 2012-04-07T18:13:04.167 に答える