• js多级菜单


    一、开篇

    上次写了一个没有任何效果的多级菜单,有朋友说直接用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;
    }

    三、示例下载

           点此下载示例

    posted @ 2008-11-08 23:50 LongWay 阅读(477) 评论(3)  编辑 收藏 网摘 所属分类: Javascript
  • 相关阅读:
    AWK只打印某个域后的所有域
    Apache配置文件httpd.conf内容翻译
    DOM事件类型详解
    DOM中的事件处理概览与原理的全面剖析
    JavaScript实战(带收放动画效果的导航菜单)
    (转)高性能JavaScript:加载和运行(动态加载JS代码)
    (转)网页性能管理详解
    (转)JavaScript-性能优化之函数节流(throttle)与函数去抖(debounce)
    你真的知道setTimeout是如何运行的吗
    用原生JS读写CSS样式的方法总结
  • 原文地址:https://www.cnblogs.com/sunfeiwto/p/1330076.html
Copyright © 2020-2023  润新知