2011-09-08 289 views
0

这里是我的下拉菜单类。而在隐藏方法中,Fininsh 之后的回调函数会丢失该类的范围。我不想为此宣布一个全球性的可变因素。有没有更好的解决方案?Javascript范围丢失问题

var DropMenu = Class.create({ 
    // Class properties. 
    speed: 0.4, 
    delay: 0, 
    active_submenu: null, 

    initialize: function() { 
     $$("li.drop_down_element").invoke('observe', 'mouseenter', this.mouseOver.bind(this)); 
     $$("li.drop_down_element").invoke('observe', 'mouseleave', this.mouseOut.bind(this)); 
    }, 

    show: function(elem, speed) { 
     new Effect.BlindDown(elem, {duration: speed, queue: {position: 'end', scope: elem.identify(), limit:13}}); 
    }, 

    hide: function(elem, speed) { 

     if(elem.visible()) 
     { 
     new Effect.BlindUp(elem, {duration: speed, queue: {position: 'end', scope: elem.identify(), limit: 13}, afterFinish: function(scope) { console.info(scope)}(this)}); 
     } 
    }, 

    mouseOver: function(event) { 
     var element = event.element(), 
      submenu = element.getElementsByClassName('submenu_element')[0], 
      width = element.getWidth(); 
     if(submenu) 
     { 
     submenu.setStyle({minWidth: width + 'px'}) 
       this.active_submenu = submenu; 
     this.show(submenu, this.speed);   
     } 
     if(!this.iefix && Prototype.Browser.IE) 
     { 
     new Insertion.After(submenu, 
     '<iframe id="dropdown_iefix" '+ 
     'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' + 
     'src="javascript:false;" frameborder="0" scrolling="no"></iframe>'); 
     this.iefix = $(submenu.id+'_iefix'); 
     } 

     //if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); 

    }, 

    mouseOut: function(event) { 

     var submenu = this.active_submenu; 


     if (submenu) 
     { 
     this.hide.delay(this.delay, submenu, this.speed); 
     } 
    }, 

    fixIEOverlapping: function() { 
     Position.clone(this.active_submenu, this.iefix, {setTop:(!this.active_submenu.style.height)}); 
     this.iefix.style.zIndex = 700; 
     this.iefix.style.border = '2px solid #000'; 
     this.active_submenu.style.zIndex = 999; 
     Element.show(this.iefix); 
    } 

    }); 
    document.observe('dom:loaded', function() { new DropMenu(); }); 

回答

1

你可以这样做:

if(elem.visible()) 
{ 
    var that = this; 
    new Effect.BlindUp(elem, { 
     duration: speed, 
     queue: {position: 'end', scope: elem.identify(), limit: 13}, 
     afterFinish: function() { console.info(that); } 
    }); 
} 

...但你可能不喜欢这个。有些浏览器支持Function.prototype.bind,它允许你创建一个绑定到你想要的范围的功能,例如:

if(elem.visible()) 
{ 
    var that = this; 
    new Effect.BlindUp(elem, { 
     duration: speed, 
     queue: {position: 'end', scope: elem.identify(), limit: 13}, 
     afterFinish: (function() { console.info(this); }).bind(this); 
    }); 
} 

如果没有Function.prototype.bind做,你可以使用这个片段(stolen from MDN)来定义它(你说你使用的是Prototype,它应该已经有了):

if (!Function.prototype.bind) { 

    Function.prototype.bind = function (oThis) { 

    if (typeof this !== "function") // closest thing possible to the ECMAScript 5 internal IsCallable function 
     throw new TypeError("Function.prototype.bind - what is trying to be fBound is not callable"); 

    var aArgs = Array.prototype.slice.call(arguments, 1), 
     fToBind = this, 
     fNOP = function() {}, 
     fBound = function() { 
      return fToBind.apply(this instanceof fNOP ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments)));  
     }; 

    fNOP.prototype = this.prototype; 
    fBound.prototype = new fNOP(); 

    return fBound; 

    }; 

}