[转帖]Mootools源码分析-50 -- Accordion

原帖地址:http://space.flash8.net/space/?uid-18713-action-viewspace-itemid-410510

原作者:我佛山人

 

代码
//类似手风琴的伸缩效果,需要结合Fx.Elements理解
//
演示:http://demos.mootools.net/Accordion

var Accordion = new Class({

    
//继承自Fx.Elements
    Extends: Fx.Elements,

    options: {
/*
        //伸展显示事件
        onActive: $empty,
        //压缩隐藏事件
        onBackground: $empty,
*/
        
//显示的索引值
        display: 0,
        
//显示的索引值
        show: false,
        
//高度的显示方式
        height: true,
        
//宽度的显示方式
        width: false,
        
//透明度的显示方式
        opacity: true,
        
//是否固定高度
        fixedHeight: false,
        
//是否固定宽度
        fixedWidth: false,
        
//是否等待前一次动画结束
        wait: false,
        
//永远隐藏
        alwaysHide: false
    },

    
//构造函数
    initialize: function()    {
        
//利用Array.link读取参数并归类
        var params = Array.link(arguments, {'container': Element.type, 'options': Object.type, 'togglers': $defined, 'elements': $defined});
        
//调用父类Fx.Elements的同名方法
        arguments.callee.parent(params.elements, params.options);
        
//取能toggle的Elements(点击时伸缩的对象)
        this.togglers = $$(params.togglers);
        
//整个UI容器
        this.container = $(params.container);
        
//最后激活的对象索引
        this.previous = -1;
        
//如果设置
        if (this.options.alwaysHide)    this.options.wait = true;
        
//如果设置显示的索引值
        if ($chk(this.options.show))    {
            
//忽略display的设置
            this.options.display = false;
            
//更新指向
            this.previous = this.options.show;
        }
        
//如果手工执行start方法
        if (this.options.start)    {
            
//忽略display指定的值
            this.options.display = false;
            
//忽略show指定的值
            this.options.show = false;
        }
        
//提供Fx.Eleemnts中变化的属性集
        this.effects = {};
        
//如果指定透明度,设效果中的透明属性值为完全透明
        if (this.options.opacity)    this.effects.opacity = 'fullOpacity';
        
//如果指定宽度,当同时指定固定宽度时,设效果中的宽度属性值为全尺寸宽度,否则为当前宽度
        if (this.options.width)    this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth';
        
//如果指定高度,当同时指定固定高度时,设效果中的高度属性值为全尺寸宽度,否则为当前高度
        if (this.options.height)    this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight';
        
//遍历处理,为每一项添加事件
        for (var i = 0, l = this.togglers.length; i < l; i++this.addSection(this.togglers[i], this.elements[i]);
        
//遍历找到显示的指定项
        this.elements.each(function(el, i)    {
            
//如果指定显示当前项
            if (this.options.show === i)    {
                
//触发onActive事件
                this.fireEvent('onActive', [this.togglers[i], el]);
            }    
else    {
                
//设置非显示项的相关CSS属性为0
                for (var fx in this.effects)    el.setStyle(fx, 0);
            }
        }, 
this);
        
//如果display有定义非0值,
        if ($chk(this.options.display))    this.display(this.options.display);
    },

    
//添加节点
    //togger为伸缩句柄,eleemnt为内容容器,pos为添加到的位置索引
    addSection: function(toggler, element, pos)    {
        
//取对象
        toggler = $(toggler);
        element 
= $(element);
        
//测试togglers集合中是否已包含toggler
        var test = this.togglers.contains(toggler);
        
//取集合长度
        var len = this.togglers.length;
        
//将toggler包含进togglers集合
        this.togglers.include(toggler);
        
//将element包含进elements集合
        this.elements.include(element);
        
//如果集合不为空,并且不包含当前项或添加位置大于0
        if (len && (!test || pos))    {
            
//取合法的位置
            pos = $pick(pos, len - 1);
            
//插入到指定索引的项前
            toggler.inject(this.togglers[pos], 'before');
            
//内容容器插入其后
            element.inject(toggler, 'after');
            
//否则,如果指定父容器并且不在集合中
        }    else if    (this.container && !test)    {
            
//插入到父容器中
            toggler.inject(this.container);
            element.inject(
this.container);
        }
        
//取当前索引值
        var idx = this.togglers.indexOf(toggler);
        
//添加单击事件监听,在单击时显示当前索引位置上的对象
        toggler.addEvent('click'this.display.bind(this, idx));
        
//如果指定高度,为了兼容,将会影响高度值的padding和boder的上下值置0
        if (this.options.height)    element.setStyles({'padding-top'0'border-top''none''padding-bottom'0'border-bottom''none'});
        
//如果指定宽度,为了兼容,将会影响宽度值的padding和boder的左右值置0
        if (this.options.width)    element.setStyles({'padding-left'0'border-left''none''padding-right'0'border-right''none'});
        element.fullOpacity 
= 1;
        
//如果设置固定宽度
        if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth;
        
//如果设置固定高度
        if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight;
        
//剪切溢出内容
        element.setStyle('overflow''hidden');
        
//如果集合中不包含当前项
        if (!test)    {
            
//设置容器相关CSS属性为0
            for (var fx in this.effects)    element.setStyle(fx, 0);
        }
        
return this;
    },

    
//显示指定索引位置上的项
    display: function(index)    {
        
//如果参数类型为对象,取对象在集合中的索引
        index = ($type(index) == 'element'? this.elements.indexOf(index) : index;
        
//如果已经开始显示并且设置要等待,或者指定索引与最后显示的相同并且不是指定永远隐藏,退出处理
        if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this;
        
//更新最后索引的指向
        this.previous = index;
        
var ōbj = {};
        
//遍历其余项,取得变化的属性集合,为start方法提供参数
        this.elements.each(function(el, i)    {
            obj[i] 
= {};
            
//计算需要隐藏的项
            var hide = (i != index) || (this.options.alwaysHide && (el.offsetHeight > 0));
            
//根据显示或隐藏触发不同的事件
            this.fireEvent(hide ? 'onBackground' : 'onActive', [this.togglers[i], el]);
            
//隐藏时设置每个属性值为0
            for (var fx in this.effects)    obj[i][fx] = hide ? 0 : el[this.effects[fx]];
        }, 
this);
        
//开始执行效果
        return this.start(obj);
    }
});

 

 

posted @ 2009-12-08 14:55  webgis松鼠  阅读(244)  评论(0)    收藏  举报