javascript的configuration/interface变换
前端由于浏览器的发展与标准的更新, 为使不同浏览器使用dom的方法兼容,使得我们开发者写脚本通常到处都是if(browser.ie)或者if(browser.version<7)随处可见的分支判断.
我把这种状况为以下几个层次/状况:
1.无需兼容,写的都是业务层次代码
2.有兼容,尽量可以通过非hack/hook方式去做到兼容处理.
3.有兼容,最好是写完兼容层次,程序继续到通用处理.
4.有兼容,需要用很多if去判断的兼容.
业务者实际上看到的就是第一种状况.
而对于前端框架代码中,由于没有规范,约束, 所以经常在维护代码中很苦恼.我们经常在第四点上苦恼.
问题
1.例如我们常遇到的兼容问题, 请尝试写一个Style.get(element, 'opacity')方法.
是不是该在Style.get里实现加入if是IE.而且<10之类的判断.
2.focusin,onmouseenter,onmouseleave事件,使得业务调用可以使用及绑定这些事件.
这样的例子可以拿出很多, 其实要说用中间层处理dom分支, 在很早的dom框架里Base2就经常看到.
在base2里经常可以看到@ie, @mozilla之类的字符串, 其实也是conf配置,中间函数分发的一种.
换个思路
如果不是针对dom编程,而是针对有一套规则,中间层针对规则去做处理,或许就能更好编程.
以下几段代码算是抛砖引玉,也许大家都有更好的思路.
解决方法
示例1, css兼容
看使用方法,cssconf配置,来看看property以及读写器的配置规则
//取值潜规则
//1.对应在map中浏览器中修正的属性值
//2.修正的读写器(一定要为函数)
//2.配置map中浏览器对应的default值
//3.最后用传参过来的默认值
//为不同浏览器配置属性的hash
//如果是纯属性值结构为
//'property': {
// 'browser': 'property-value'
// 'default': 'default-value'
//}
//如果是读写器函数,结构为
//'property': {
// 'browser': {
// set: function(el, css, value) {}
// get: function(el, css, value) {}
// }
//}
var cssconf = {
'transition': {
'ie' : '-ms-transition',
'webkit' : '-webkit-transition',
'firefox': '-moz-transition',
'opera' : '-o-transition'
},
'float' : { 'default': 'cssFloat' },
'opacity' : {
'ie' : {
set: function(el, css, value) {
value = parseFloat(value) || 1;
var styleObject = el.style;
//如果设置的透明度为1时,IE里去除alpha通道的滤镜
var result = (1 != value) ? 'alpha(opacity=' +(value*100)+ ')' : '';
styleObject.filter = (styleObject.filter||'').replace(/alpha\\(opacity=(.*)\\)/gi, '') +result;
//IE里filter需要触发hasLayout属性
styleObject.zoom = 1;
return value;
},
get: function(el, css, presudo) {
var result = '';
if (result = (Style.get(el, 'filter') || '').match(/opacity=(.*)/i)) {
if (result && result[1]) {
return parseInt(result[1], 10)/100;
}
}
return 1;
}
}
}
}
https://github.com/ranklau/marmot/tree/master/labs/style
示例2, 用typedef来进行dom事件兼容
先看看结果代码:
//思路借鉴到脚本里,含义是将某个类型经过转化,可以定义成另一类型,如:
//用typedef去做了个hook使mouseenter和mouseleave都能得以兼容所有浏览器
_typedef('mouseover', 'mouseenter', function(e, handler) {
var el = this, target = e.relatedTarget || e.fromElement || null;
if (!target || target == el || dom.contains(el, target)) { return null; }
return handler.call(el, e);
});
https://github.com/ranklau/marmot/blob/master/labs/typedef
为了兼容而兼容吗?
代码如果仅仅为了兼容而兼容那太悲催了.
如果我们把这个思路扩展开,则是针对规范接口编程的一种解耦方式.
用这种变换的思路可以做很多事.
例如qwrap里的jss.示例3, 用jss来进行dom与js解耦
".d": {dataType:'d', minValue:'2008-01-01'},
".n": {dataType:'n', minValue:0},
".email": {dataType:'email'},
'#fromDate': {minValue:'2011-11-12'}
});
alert(W('#fromDate').jss('minValue'));
框架层次的代码
这个示例没有代码.
通过中间层去作变换,添加一些功能.从设计模式的理解是针对这样的模式有一个例子: decorator.我们所说的函数变换,在常规语言里的大多数场景里都是decorator. --- 动态地给一个对象/函数添加一些额外的职责.
js的函数用起来爽的一个很重要原因是不用去声明接口,不用再添加一个额外的Object/Class去处理中间层,只用一个函数+closure的方式轻松实现.
我们可以试想, 在多个不同的ui类里,你得写多少一样的代码?
写show, hide,还得支持自定义事件.
构造函数还要加if分支第一个是HTMLElement,需要调用render,是json则create.
在需要链式调用的地方,你得需要写多少个return this?
如果有decorate,你将不用写这些一样的代码.同时还可以约束大家的代码结构与接口.
这种变换不是继承关系,而是组合关系.能使你的代码更易于维护. 结构上更清晰.
总之,程序中有合理的规则,接口约束,是通用处理与变换的基础.
P.S,今天有点晕,语法可能有点不通顺,以后有空再改改,凑合着看吧.
seealso:
降低HTML结构与脚本之间的强耦合 http://www.never-online.net/blog/article.asp?id=256
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:Rank <null@null.com> 来源: rank's technical notes
- 标签: configuration interface
- 发布时间:2012-01-29 20:53:26
- [67] Oracle MTS模式下 进程地址与会话信
- [65] 如何拿下简短的域名
- [65] Go Reflect 性能
- [59] 图书馆的世界纪录
- [59] android 开发入门
- [59] 【社会化设计】自我(self)部分――欢迎区
- [58] IOS安全–浅谈关于IOS加固的几种方法
- [53] 视觉调整-设计师 vs. 逻辑
- [47] 读书笔记-壹百度:百度十年千倍的29条法则
- [46] 界面设计速成