[转帖]Mootools源码分析-18 -- Element-5
原帖地址:http://space.flash8.net/space/?uid-18713-action-viewspace-itemid-403396
原作者:我佛山人
//Element的styles的setter,setStyles的快捷方式
Element.Properties.styles = {set: function(styles) {
this.setStyles(styles);
}};
//Element的透明度控制在浏览器间差异较大,所以单独处理
Element.Properties.opacity = {
set: function(opacity, novisibility) {
//如果没有指定不控制visibility样式(即仅当novisibility参数为true时不处理)
if (!novisibility) {
//所以要控制隐藏与显示,可以用this.set('opacity', 1)和this.set('opacity', 0)来控制
if (opacity == 0) {
//透明度为0时直接隐藏
if (this.style.visibility != 'hidden') this.style.visibility = 'hidden';
} else {
//透明度为1时直接显示
if (this.style.visibility != 'visible') this.style.visibility = 'visible';
}
}
//修正ie hasLayout的bug
if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
//ie的透明度控制用滤镜,注意两种opacity值的区别
if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')';
//非ie直接用opacity样式属性
this.style.opacity = opacity;
//存到临时对象,以避免读取时再次进行兼容性判断和操作
this.store('opacity', opacity);
},
//直接取临时对象数据,省却兼容性问题
get: function() {
return this.retrieve('opacity', 1);
}
};
Element.implement({
//设置透明度的快捷方式
setOpacity: function(value) {
return this.set('opacity', value, true);
},
//获取透明度
getOpacity: function() {
return this.get('opacity');
},
//样式设置
setStyle: function(property, value) {
//两个特殊属性
switch (property) {
case 'opacity': return this.set('opacity', parseFloat(value));
case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
}
/*
转成骆驼表示,所以其实这里的样式属性同时支持两种写法,如
setStyle('borderTopWith', 1) 和 setStyle('border-top-with', 1)
*/
property = property.camelCase();
if ($type(value) != 'string') {
var map = (Element.Styles.get(property) || '@').split(' ');
//处理多属性简写时的赋值
value = $splat(value).map(function(val, i) {
if (!map[i]) return '';
return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
}).join(' ');
} else if (value == String(Number(value))) {
value = Math.round(value);
}
this.style[property] = value;
return this;
},
//获取样式值
getStyle: function(property) {
//还是那两个特殊属性
switch (property) {
case 'opacity': return this.get('opacity');
case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
}
//还是支持两种写法
property = property.camelCase();
var result = this.style[property];
//如果取不到值(通常是因为是简写的属性或者属性是在css中指定)
if (!$chk(result)) {
result = [];
//将简写属性还原,逐个取值
for (var style in Element.ShortStyles) {
if (property != style) continue;
for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
return result.join(' ');
}
//另一种可能,样式是在<style>中指定或者外部css文件指定,这时需要获取运行时的样式值
result = this.getComputedStyle(property);
}
if (result) {
//颜色处理,将RGB表示转成HEX表示
result = String(result);
var color = result.match(/rgba?\([\d\s,]+\)/);
if (color) result = result.replace(color[0], color[0].rgbToHex());
}
//在Opera和IE下,获取width和height的处理
if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result)))) {
//IE和Opera的width不会计算边框厚度,而遵循w3c标准的Fx会
if (property.test(/^(height|width)$/)) {
var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
values.each(function(value) {
size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
}, this);
//用offsetWidth/offsetHeight减相应方向的边框厚度即为所求
return this['offset' + property.capitalize()] - size + 'px';
}
if (Browser.Engine.presto && String(result).test('px')) return result;
if (property.test(/(border(.+)Width|margin|padding)/)) return '0px';
}
return result;
},
//批量设置样式
setStyles: function(styles) {
for (var style in styles) this.setStyle(style, styles[style]);
return this;
},
//批量获取样式
getStyles: function() {
var result = {};
Array.each(arguments, function(key) {
result[key] = this.getStyle(key);
}, this);
return result;
}
});
//一些特殊的样式,只是待加工的材料
Element.Styles = new Hash({
left: '@px', top: '@px', bottom: '@px', right: '@px',
width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
});
//一些缮写的样式,只是待加工的材料
Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
//对Element.Styles和Element.ShortStyles的再加工
['Top', 'Right', 'Bottom', 'Left'].each(function(direction) {
var Short = Element.ShortStyles;
var All = Element.Styles;
//构造marginTop,paddingTop之类的属性
['margin', 'padding'].each(function(style) {
var sd = style + direction;
Short[style][sd] = All[sd] = '@px';
});
//构造borderTopWith之类的属性
var bd = 'border' + direction;
Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
Short[bd] = {};
Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
});
Element.Properties.styles = {set: function(styles) {
this.setStyles(styles);
}};
//Element的透明度控制在浏览器间差异较大,所以单独处理
Element.Properties.opacity = {
set: function(opacity, novisibility) {
//如果没有指定不控制visibility样式(即仅当novisibility参数为true时不处理)
if (!novisibility) {
//所以要控制隐藏与显示,可以用this.set('opacity', 1)和this.set('opacity', 0)来控制
if (opacity == 0) {
//透明度为0时直接隐藏
if (this.style.visibility != 'hidden') this.style.visibility = 'hidden';
} else {
//透明度为1时直接显示
if (this.style.visibility != 'visible') this.style.visibility = 'visible';
}
}
//修正ie hasLayout的bug
if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
//ie的透明度控制用滤镜,注意两种opacity值的区别
if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')';
//非ie直接用opacity样式属性
this.style.opacity = opacity;
//存到临时对象,以避免读取时再次进行兼容性判断和操作
this.store('opacity', opacity);
},
//直接取临时对象数据,省却兼容性问题
get: function() {
return this.retrieve('opacity', 1);
}
};
Element.implement({
//设置透明度的快捷方式
setOpacity: function(value) {
return this.set('opacity', value, true);
},
//获取透明度
getOpacity: function() {
return this.get('opacity');
},
//样式设置
setStyle: function(property, value) {
//两个特殊属性
switch (property) {
case 'opacity': return this.set('opacity', parseFloat(value));
case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
}
/*
转成骆驼表示,所以其实这里的样式属性同时支持两种写法,如
setStyle('borderTopWith', 1) 和 setStyle('border-top-with', 1)
*/
property = property.camelCase();
if ($type(value) != 'string') {
var map = (Element.Styles.get(property) || '@').split(' ');
//处理多属性简写时的赋值
value = $splat(value).map(function(val, i) {
if (!map[i]) return '';
return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
}).join(' ');
} else if (value == String(Number(value))) {
value = Math.round(value);
}
this.style[property] = value;
return this;
},
//获取样式值
getStyle: function(property) {
//还是那两个特殊属性
switch (property) {
case 'opacity': return this.get('opacity');
case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
}
//还是支持两种写法
property = property.camelCase();
var result = this.style[property];
//如果取不到值(通常是因为是简写的属性或者属性是在css中指定)
if (!$chk(result)) {
result = [];
//将简写属性还原,逐个取值
for (var style in Element.ShortStyles) {
if (property != style) continue;
for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
return result.join(' ');
}
//另一种可能,样式是在<style>中指定或者外部css文件指定,这时需要获取运行时的样式值
result = this.getComputedStyle(property);
}
if (result) {
//颜色处理,将RGB表示转成HEX表示
result = String(result);
var color = result.match(/rgba?\([\d\s,]+\)/);
if (color) result = result.replace(color[0], color[0].rgbToHex());
}
//在Opera和IE下,获取width和height的处理
if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result)))) {
//IE和Opera的width不会计算边框厚度,而遵循w3c标准的Fx会
if (property.test(/^(height|width)$/)) {
var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
values.each(function(value) {
size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
}, this);
//用offsetWidth/offsetHeight减相应方向的边框厚度即为所求
return this['offset' + property.capitalize()] - size + 'px';
}
if (Browser.Engine.presto && String(result).test('px')) return result;
if (property.test(/(border(.+)Width|margin|padding)/)) return '0px';
}
return result;
},
//批量设置样式
setStyles: function(styles) {
for (var style in styles) this.setStyle(style, styles[style]);
return this;
},
//批量获取样式
getStyles: function() {
var result = {};
Array.each(arguments, function(key) {
result[key] = this.getStyle(key);
}, this);
return result;
}
});
//一些特殊的样式,只是待加工的材料
Element.Styles = new Hash({
left: '@px', top: '@px', bottom: '@px', right: '@px',
width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
});
//一些缮写的样式,只是待加工的材料
Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
//对Element.Styles和Element.ShortStyles的再加工
['Top', 'Right', 'Bottom', 'Left'].each(function(direction) {
var Short = Element.ShortStyles;
var All = Element.Styles;
//构造marginTop,paddingTop之类的属性
['margin', 'padding'].each(function(style) {
var sd = style + direction;
Short[style][sd] = All[sd] = '@px';
});
//构造borderTopWith之类的属性
var bd = 'border' + direction;
Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
Short[bd] = {};
Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
});