[转帖]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);
}
});
//演示: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);
}
});


浙公网安备 33010602011771号