首页 > 网站 > WEB开发 > 正文

第九章:样式模块

2024-04-27 14:06:54
字体:
来源:转载
供稿:网友

第九章:样式模块

样式模块分为两大块,精确获取样式值与设置样式,精确是用于修饰符获取的。由于样式分布为外部样式,内部样式与行内样式,再加个impotant对选择器的权重的干扰,我们实际很难看到元素是应用了那块的样式。因此,样式模块,80%的比重在于获取这一块,像offset,滚动条也纳入这一块。

大体上,我们在标准浏览器是使用getComputedStyle,ie6-8使用currentStyle来获取元素的精确样式。不过,getComputedStyle并不挂在元素上,而是window的一个API,它返回一个对象,可以选择使用getPRopertyValue方法传入连字符风格的样式名取得其值 ,或者属性法+驼峰风格的样式名去取值。但考虑到currentStyle也是使用属性法+驼峰风格,我们就统一使用后者。

    var getStyle = function (el, name) {        if (el.style) {            name = name.replace(//-(/w)/g,function(all,letter) {                return letter.toUpperCase();            });            if (window.getComputedStyle) {                //getComputedStyle的第二个伪类是用于对付伪类的,如滚动条,placeholder,                //但ie9不支持,因为我们只管元素节点,上面的el.style过滤掉了                return el.ownerDocument.getComputedStyle(el, null)[name]            } else {                return el.currentStyle[ name ]            }        }    }

设置样式则更是没有难度,直接el.style[name]=value搞定

但框架要考虑的东西更多,如兼容性,易用性,扩展性

1.样式名要同时支持连字符风格(CSS的标准风格),与驼峰风格(DOM的标准风格)

2.样式名要进行必要的处理,如float样式与css3带私有前缀的样式

3.如果框架是仿jQuery风格,要考虑set all get frist

4.设置样式时,对长度宽度可以考虑直接处理数值,比如由框架智能补上px单位。

5.设置样式时,对于长宽度可以考虑传入相对值,如"-=20"

6.对于个别的样式特殊处理,如IE下的z-index,opacity,user-select,background-position,top,left

7.基于setStyle,getStyle的扩展,height,width,offset等方法。

在学习过程中,对css模块与css_fix模块进行展开。涵盖的内容相当于jQuery的css,offset,demensions模块,也相当于EXT4的Element.style Element.scroll, Element.position模块。

https://github.com/jiayi2/mass-Framework/blob/master/css.jshttps://github.com/jiayi2/mass-Framework/blob/master/css_fix.js

其中,css_fix用于兼容旧版的IE,涉及的API有css,cssName,cssNumber,cssHooks,height,width,innerHeight,innerWidth,outerWidth,offset,position,scrollTop,scrollLeft,show,hide,toggle,offsetParent,scrollParent。

放在$上为静态方法,放在$.fn上的为原型方法。独立于这两者的为私有方法或对象

一.样式名的修正

不是所有的样式名都是用正则简单的处理一下就行,这里存在三个陷阱,float对于的javascript属性存在兼容性问题css3带来的私有前缀ie的私有前缀不和流等问题

私有前缀是css3的实现和标准滞后所带来的问题,其实私有前缀-ms-在ie8时代就存在了,-khtml-就更早了。现在私有前缀如下:

浏览器ieFirefoxChromesafariOperaKonqueror
前缀-ms--moz--webkit--webkit--o--khtml-

2013年,google嫌webkit内核态臃肿,决定自己单干,取名blink,并在chrome28起使用此内核,为了减轻用户负担,还是使用webkit做前缀,目前,2013年,google嫌webkit内核态臃肿,决定自己单干,取名blink,并在chrome28起使用此内核,为了减轻用户负担,还是使用webkit做前缀,目前,使用-webkit-前缀的有Opera,Safari,Chrome三家。

上述的这些前缀加上样式名再驼峰化就是真正可用的样式名,比如-ms-transform -> MsTransform, -webkit-transform ->WebKitTransform, -o-transform -> Otransform 。但这些实验性的样式会迟早退出历史舞台,它们会卸载掉前缀从新亮相,比如ff17下就可以直接使用transfrom。但光是这样不够,还有第三个问题IE下的-ms-trabsform的Javascript属性名msTransform,因此,搞定这个正则就特别复杂,我们要动用一个函数通过侦测手段获取它。在mass,它叫cssName,在jQuery,它叫vendorPropName。由于特征侦测是DOM操作,消耗很大,因此获取后就应该缓存起来,避免重复检测,这个对象在mass称为cssMap.

    var prefixes = ['', '-webkit-', '-moz-', '-ms-', '-o-'];    var cssMap = {        "float": $.support.cssFloat ? 'cssFloat' : 'styleFloat', background : "backgroundColor"    };    function cssName(name, host, camelCase) {        if (cssMap[name]) {            return cssMap[name];        }        host = host || document.documentElement        for (var i = 0, n = prefixes.length; i < n; i++) {            camelCase = $.String.camelCase(prefixes[i] + name);            if (camelCase in host) {                return (cssMap[name] = camelCase)            }        }        return null;    }

prefixes的顺序设置得相当有技巧,“”表示没有私有前缀, 此样式已经标准化,所有在最前。-webkit- , -o-依次排开。

通过上面的函数,我们只需传入一个参数,就可以得到真正可用的样式名了。

一:个别样式的特殊处理

让我们来展示cssHooks的价值所在,它是专门用于对付那些有兼容性的问题,不按常规出牌的奇葩样式。cssHooks为一个普通的对象。每个属性名都以xxx+":set"或xxx+":get"命名,值为处理函数。

1。opacity。

.opacity{opacity:.5}opacity会让背景与内容变得透明想内容不透明,就要用rgba与hsla。不过它们是一种值的格式,并不是样式。

ie依赖滤镜DXImageTransform.Microsoft.Alpha,不过IE提供了一个简短的

.opacity{fliter:alpha(opacity=40)

}

在ie6 7需要注意,为了使得透明设置生效,元素必须是“有布局”。一个元素可以通过一些css属性来使其被布局,有如width和position.关于微软专有的hasLayout属性详情,以及如何触发它,可以看下面的链接。

http://www.blueidea.com/tech/site/2006/3698.asp

2.background-position

旧版ie中,ie只支持backgrounPositionX与backgroundPositionY,不支持backgroundPosition。实现很简单,分别提取backgrounPositionX与backgroundPositionY,然后拼合他们。

    adapter["backgroundPosition:get"] = function(node, name, value) {        var style = node.currentStyle;        return style.backgroundPositionX + " " + style.backgroundPositionY    };

3.z-index

z-index是一个并不难理解的属性,但它因为错误的假设使一些开发人员陷入混乱。混乱发生的原因是因为z-index只能工作在被明确定义了absolute,fixed,relative这三个定位属性元素中,它会让元素沿着z轴进行排序(z轴的起点为父节点所在的层,终点为屏幕)。

z-index在下拉菜单,tooltip,灯箱效果中,相册与拖动中经常被使用。为了让目标控件排在最前,我们需要得知他们的z-index,然后有目的的改z-index,然后有目的的改z-index或重排元素(将目标元素移除dom树,再插入父元素最后的一个元素之后)。

想获取z-index,这里应对一个特殊情况,目标元素没有被定位,需要往上回溯到其祖先定位元素。如果找到,就返回祖先的z-index.如果最后也没找到,就返回0.

    adapter["zIndex:get"] = function (node) {        while (node.nodeType !== 9) {            //即使元素定为了,但如果z-index的值设置为 "aaa"这样的无效值。浏览器都会返回auto            //如果没有指定z-index值,ie会返回0。其它返回auto        var position = getter(node, "position") || "static";        if (position !== "static") {            // <div style="z-index:-10;" ><div style="z-index:0;"></div></div>            var value = parseInt(getter(node, "zIndex"),10);            if (!isNaN(value) && value !== 0) {                return value;            }        }        node = node.parentNode;       }       return 0    }

4.元素的隐显

元素的隐藏与显示在页面上实现由很多办法,这里只说明下display。display为none时,它不再占有物理空间,附近的元素就顺势挪过去,比如手风琴效果,下拉效果都依赖于此。

    $.fn.show = function() {        return this.each(function() {            this.style.display = "";        })    }    $.fn.hide = function() {        return this.each(function() {            this.style.display = "none";        })    }    $.fn.toggle = function() {        return this.each(function() {            this.style.display = isHidden(this) ? "" : "none";        })    }    $.fn.isHidden = function(node) {        return node.sourceIndex === 0 ||        getter(node, "display") === "none" ||        !$.contains(node.ownerDocument, node);    }

然后我们创建一个方法,把$.fn.show, $.fn.hide, $.fn.toggle功能全部交给它做。

    function toggleDisplay(nodes, show) {        var elem, values = [],            status = [],            index = 0,            length = nodes.length;    //由于传入的元素们可能存在包含关系,因此分开两个循环来处理,度土匪循环用于取得当前值或默认值    for (; index < length; index++) {        elem = nodes[index];        if (!elem.style) {            continue;        }        values[index] = $._data(elem, "olddisplay");        status[index] = $.isHidden(elem);        if (!values[index]) {            values[index] = status[index] ? $.parseDispaly(elem.nodeName) : getter(elem,"display");            $._data(elem,"olddisplay",values[index]);        }    }    //第二个循环用于样式设置,-1为toggle,1为show,0为hide    for (index = 0, index < length; index++) {        elem = nodes[index];        if (elem.style) {            continue;        }        show = show === -1 ? !status[index] : "none";    }    return nodes    }

最后,我们只要稍微在外面一层就能实现与jQuery功能一样的show,hide,toggle,这样做还有一个好处,就是接口与实现分离

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表