Javascript多级菜单(二)

一、开篇

上次写了一个没有任何效果的多级菜单,有朋友说直接用CSS就可以实现,所以就继续加工了一下,做了两个用CSS不能实现的菜单,效果如下:

渐变多级菜单
滑动多级菜单

二、原理

修改了一下上一篇中的代码,再次总结一下原理:

 

主要是要响应4个事件:菜单项(MenuItem.element,是一个li)的mouseover和mouseout以及子菜单MenuItem.childMenu,是一个ul)的mouseover和mouseout事件。这几种事件都可能因为其子元素的冒泡而重复发生,可以利用上一篇介绍的方法,判断relatedTarget来防止这种事情的发生。

var  target  =  e.element();
var  relatedTarget  =  e.relatedTarget  ||  e.fromElement;
if ( ! relatedTarget) return ;
if ($(relatedTarget).descendantOf(self.element)  ||  $(relatedTarget)  ==  self.element)
    
return ;
  • MenuItem.element.mouseover事件:鼠标移动到菜单项时,先要关闭同一级的其他菜单,然后要设置当前子菜单的位置,然后打开当前的子菜单,并且需要打开当前菜单之上的所有菜单;
  • MenuItem.element.mouseout事件:关闭当前菜单的子菜单;
  • MenuItem.childMenu.mouseover事件:清除当前菜单及之上的所有菜单的关闭延时,关闭延时是防止鼠标移出菜单过后菜单马上消失;
  • MenuItem.childMenu.mouseout事件:开始关闭当前菜单以及之上的所有菜单的延时;

打开子菜单和关闭子菜单是通过MenuItem的open和close方法来实现的,但是响应上面四个鼠标事件的过程中,可能会反复调用某个菜单的open和close方法,这样给菜单制作带来了很大的麻烦,尤其是对于渐变和滑动的菜单,重复的open和close会导致菜单产生很多怪异的行为。所以,在MenuItem里面添加了closed这个属性来标志当前子菜单的状态。在open和close调用的时候都需要先判断,如果已经打开了就不能再次打开但是可以关闭,反之亦然。

最简单的open和close方法如下:

open: function (){ // 立即打开当前菜单
     if ( ! this .isClosed) return ; // 保证不重复打开
     this .clearCloseTimeout();
    
this .menu.liFocus( this );
    
if ( this .childMenu){
        
this .childMenu.show();
        writeLog(
this .name  +   "  childMenu show " );
    }
    
this .isClosed  =   false ;
},
close: function (){ // 立即关闭当前菜单
     if ( this .isClosed) return ; // 保证不重复关闭
     this .clearCloseTimeout();
    
this .menu.liBlur( this );
    
if ( this .childMenu){
        
this .childMenu.hide();
        writeLog(
this .name  +   "  childMenu hide " );
    }
    
this .isClosed  =   true ;
},

 

 对于渐变菜单和滑动菜单,就可以集中来解决做渐变和滑动效果,其他的变化不是很大(滑动菜单的render不一样)。

对于渐变菜单,就是设置一下透明度:

open: function (){ // 立即打开当前菜单
     this .clearCloseTimeout();
    
if ( ! this .isClosed) return ; // 保证不重复打开
     this .menu.liFocus( this );
    
if ( this .childMenu){
        clearInterval(
this .fadeInIntervalId);
        clearInterval(
this .fadeOutIntervalId);
        
var  self  =   this ;
        
var  init  =   0 ;
        
this .childMenu.setOpacity(init);
        
this .childMenu.show();
        
function  fadeIn(){
            init 
+=   0.1 ;
            
if (init  >=   1 )
                init 
=   1 ;
            self.childMenu.setOpacity(init);
            
if (init  ==   1 ){
                clearInterval(self.fadeInIntervalId);
                
// self.isClosed = false;
            }
        }
        
this .fadeInIntervalId  =  setInterval(fadeIn, 30 );
        writeLog(
this .name  +   "  childMenu show " );
    }
    
this .isClosed  =   false ;
}

close: function (){ // 立即关闭当前菜单
     this .clearCloseTimeout();
    
if ( this .isClosed) return ; // 保证不重复关闭
     this .menu.liBlur( this );
    
if ( this .childMenu){
        clearInterval(
this .fadeInIntervalId);
        clearInterval(
this .fadeOutIntervalId);
        
var  self  =   this ;
        
var  init  =   1 ;
        
this .childMenu.setOpacity(init);
        
function  fadeOut(){
            init 
-=   0.1 ;
            
if (init  <=   0 )
                init 
=   0 ;
            self.childMenu.setOpacity(init);
            
if (init  ==   0 ){
                clearInterval(self.fadeOutIntervalId);
                self.childMenu.hide();
            }
        }
        
this .fadeOutIntervalId  =  setInterval(fadeOut, 10 );
        writeLog(
this .name  +   "  childMenu hide " );
    }
    
this .isClosed  =   true ;
}

 对于滑动菜单,原理可以参看以前的介绍滑动菜单的文章:滑动菜单(一)滑动菜单(二)

滑动菜单的open和close如下:

 

open: function (){ // 立即打开当前菜单
     this .clearCloseTimeout();
    
if ( ! this .isClosed) return ; // 保证不重复打开
     this .menu.liFocus( this );
    
if ( this .childMenu){
        clearInterval(
this .slideInIntervalId);
        clearInterval(
this .slideOutIntervalId);
        
this .childMenuContainer.show();
        
var  self  =   this ;
        
var  start  =   0 ;
        
if ( this .depth  ==   0 )
            start 
=  parseInt( this .childMenu.getStyle( " top " ));
        
else
            start 
=  parseInt( this .childMenu.getStyle( " left " ));
        
        
var  end  =   0 ;
        
function  slideIn(){
            
var  step  =  Math.round((end  -  start) / 5);
            start  +=  step;
            
if (start  >=  end  ||  step  ==   0 )
                start 
=  end;
            
if (self.depth  ==   0 )
                self.childMenu.setStyle({
                    
" top " :start  +   " px "
                });
            
else
                self.childMenu.setStyle({
                    
" left " :start  +   " px "
                });
            
if (start  ==  end){
                clearInterval(self.slideInIntervalId);
                self.isClosed 
=   false ;
            }
        }
        
this .slideInIntervalId  =  setInterval(slideIn, 15 );
        writeLog(
this .name  +   "  childMenu show " );
    }
    
this .isClosed  =   false ;
}

close: function (){ // 立即关闭当前菜单
     this .clearCloseTimeout();
    
if ( this .isClosed) return ; // 保证不重复关闭
     this .menu.liBlur( this );
    
if ( this .childMenu){
        clearInterval(
this .slideInIntervalId);
        clearInterval(
this .slideOutIntervalId);
        
var  self  =   this ;
        
var  start  =   0 ;
        
if ( this .depth  ==   0 )
            start 
=  parseInt( this .childMenu.getStyle( " top " ));
        
else
            start 
=  parseInt( this .childMenu.getStyle( " left " ));
            
        
var  end  =   0 ;
        
if ( this .depth  ==   0 )
            end 
=   - this .childMenu.getHeight();
        
else
            end 
=   - this .childMenu.getWidth();
        
        
function  slideOut(){
            
var  step  =  Math.round((start  -  end) / 5);
            start  -=  step;
            
if (start  <=  end  ||  step  ==   0 )
                start 
=  end;
            
            
if (self.depth  ==   0 )
                self.childMenu.setStyle({
                    
" top " :start  +   " px "
                });
            
else
                self.childMenu.setStyle({
                    
" left " :start  +   " px "
                });
            
if (start  ==  end){
                clearInterval(self.slideOutIntervalId);
                
// self.isClosed = false;
                self.childMenuContainer.hide();
            }
        }
        
this .slideOutIntervalId  =  setInterval(slideOut, 30 );
        writeLog(
this .name  +   "  childMenu hide " );
    }
    
this .isClosed  =   true ;
}

三、示例下载

       点此下载示例

转载于:https://www.cnblogs.com/LongWay/archive/2008/11/08/1329785.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值