技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> JavaScript --> javascript的configuration/interface变换

javascript的configuration/interface变换

浏览:949次  出处信息
前言

    前端由于浏览器的发展与标准的更新, 为使不同浏览器使用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;

    }

    }

    }

    }

code & demo :

    https://github.com/ranklau/marmot/tree/master/labs/style

    示例2, 用typedef来进行dom事件兼容

    先看看结果代码:

//typedef, 是C里用了重定义类型的方法, 常见于定义struct.

    //思路借鉴到脚本里,含义是将某个类型经过转化,可以定义成另一类型,如:

    //用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);

    });

code & demo:

    https://github.com/ranklau/marmot/blob/master/labs/typedef

    为了兼容而兼容吗?

    代码如果仅仅为了兼容而兼容那太悲催了.

    如果我们把这个思路扩展开,则是针对规范接口编程的一种解耦方式.

    用这种变换的思路可以做很多事.

    例如qwrap里的jss.示例3, 用jss来进行dom与js解耦

Jss.addRules({

    ".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

QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1