第十二章:DOM2 和 DOM3(样式)

来源:互联网 发布:换手率数据 下载 编辑:程序博客网 时间:2024/05/19 05:01

  • DOM2 和 DOM3
    • 样式
      • 访问元素的样式
        • DOM样式属性和方法
        • 计算的样式
      • 操作样式表
        • CSSRule
        • 创建规则
        • 删除规则
      • 元素大小
        • 偏移量
        • 客户区大小
        • 滚动大小
        • 确定元素大小

DOM2 和 DOM3

样式

  • 在HTML中定义样式的方式有3种:通过<link/>元素包含外部样式表文件,通过<style>元素定义嵌入式样式,以及使用style特性定义针对特定元素的样式。DOM Level 2 Style围绕这3个应用样式的机制提供了一套API。可以用下列代码确定浏览器是否支持DOM Level 2 Style。
    var supportsDOM2CSS = document.implementation.hasFeature("CSS", "2.0");    var supportsDOM2CSS2 = document.implementation.hasFeature("CSS2", "2.0");

访问元素的样式

  • 任何支持style特性的HTML元素在JavaScript中都有一个对应的style属性。这个style对象是CSSStyleDeclaration的实例,包含这通过HTML的style特性指定的所有样式信息,但不包含与外部样式表或嵌入样式表经层叠而来的样式。在style特性中指定的任何CSS属性都将表现为这个style对象的相应属性。对于有短划线的CSS属性名,必须将其转换为驼峰大小写形式。
CSS属性 JavaScript属性 background-image style.backgroundImage color style.color display style.display font-family style.fontFamily

- 有个属性需要注意,那就是float。在JS中float是保留字,因此不能做属性名(书上原话)。经过前面的阅读可知,使用保留字未必会发生错误,也许最新的浏览器都已经可以使用float了。实验下来结果如下:

    <div id="myDiv" style="float: left"></div>    <script type="text/javascript">        var div = document.getElementById("myDiv");        console.log(div.style.float);//IE9、8:left  Chrome:left        console.log(div.style.cssFloat);//IE9:left IE8:undefined Chrome:left        console.log(div.style.styleFloat);//IE9、8:left  Chrome:undefined    </script>
  • 只要取得一个有效的DOM元素的引用,就可以随时通过JavaScript为其设置样式。
    <div id="myDiv" style="float: left">1</div>    <script type="text/javascript">        var div = document.getElementById("myDiv");        div.style.backgroundColor = "red";        div.style.width = "100px";//在混杂模式下不加px后缀没关系,在标准模式下会失效。        div.style.height = "200px";    </script>
  • 通过style对象同样可以取得在style特性中指定的样式
    <div id="myDiv" style="float: left;background-color: red;">1</div>    <script type="text/javascript">        var div = document.getElementById("myDiv");        alert(div.style.backgroundColor);//red        alert(div.style.float);//left    </script>
  • 如果没有为元素设置style特性,那么style对象中可能包含一些默认的值,但这些值并不能反映该元素的特性。
<!DOCTYPE html><html><head>    <title>DOM Level 2 IFrame Example</title>    <style>        #myDiv {            background-color: red;        }    </style></head><body>    <div id="myDiv" style="float: left">1</div>    <script type="text/javascript">        var div = document.getElementById("myDiv");        alert(div.style.backgroundColor);//"" 而不是"red"    </script></body></html>

DOM样式属性和方法

  • 下面是DOM Level 2 style规范为style对象定义的属性和方法:
    1. cssText:返回style特性中的css代码
    2. length:应用给元素的CSS属性的数量
    3. parentRule:表示CSS信息的CSSRule对象(后续讨论)。
    4. getPropertyCSSValue(propertyName):返回包含给定属性值的CSSValue对象(后续讨论)。
    5. getPropertyPriority(propertyName):如果给定的属性使用了!important设置(提高指定CSS样式规则的应用优先权),则返回”important”,否则返回空字符串。
    6. getPropertyValue(propertyName):返回给定属性的字符串值
    7. item(index):返回给定位置的CSS属性的名称(等同方括号语法,不过返回的是名称而不是
    8. removeProperty(propertyName):删除属性
    9. setProperty(propertyName,value,priority):添加或设置属性,并加上优先权标志(”important”或”“)
  • 来看下面的例子
    <div id="myDiv" style="float:left;background-color:  red;">1</div>    <script type="text/javascript">        var div = document.getElementById("myDiv");        //冒号后面的空格会被设置为1个。无论原格式如何,可见内部进行过解析。        console.log(div.style.cssText);//"float: left; background-color: red;"        //重写cssText,会移除原有属性,重新添加属性。        div.style.cssText = "float:right"//省略分号        console.log(div.style.cssText);//"float: right;" 不再保留background-color属性,且结果同样也多了空格和分号        //length的作用主要是拿来遍历        var test_div = document.createElement("div");        test_div.style.cssText = "width: 25px; height: 100px; background-color: red;";        console.log(test_div.style.length);//3        for (var i=0, len=test_div.style.length; i<len; i++) {            console.log(test_div.style[i]);//等价于 test_div.style.item(i)。            // 这里和普通的方括号语法不同地方是,在这里会返回propertyName而不是value。注意此时取到的不是驼峰命名!        }        console.log(test_div.style["width"]);//另外一种方括号用法,等价于test_div.style.getPropertyValue("width")        console.log(test_div.style.getPropertyValue("width"));//同上        //console.log(test_div.style.getPropertyCSSValue("width")); //IE、Chrome 没有这个方法        console.log(test_div.style.parentRule); //null 目前还不知道有什么用        console.log(test_div.style.getPropertyPriority("width"));//""        test_div.style.setProperty("width", "50px", "important");        console.log(test_div.style.cssText);//"width: 50px !important; height: 100px; background-color: red;"        console.log(test_div.style.getPropertyPriority("width"));//"important"        test_div.style.removeProperty("width");        console.log(test_div.style.cssText);//"height: 100px; background-color: red;"    </script>
  • 书上说了一些getPropertyCSSValue(propertyName)getPropertyValue(propertyName)的区别。后者只返回属性值的字符串表示。而前者返回一个包含两个属性的CSSValue对象,这两个属性分别是cssTextcssValueType。其中cssText属性的值和getPropertyValue(propertyName)获得的字符串相同,而cssValueType属性则是一个数值常量。0表示继承,1表示基本的值,2表示值列表,3表示自定义的值。书上说IE 9+、Safari 3+、Chrome支持这个方法?!反正我测试是not a function。这里就不再过多研究了。

计算的样式

  • 所谓计算的样式,就是元素最终的样式!前面提到的关于style对象的一些方法和属性只能够获得style特性下的样式信息,它并不包含那些从其他样式层叠而来并影响当前元素的样式信息。DOM Level 2 Style增强了document.defaultView,提供了getComputedStyle()方法。该方法接收2个参数,第一个参数是需要取得计算样式的元素,第二个参数是一个伪元素字符串(例如”:after”,这个概念涉及其他知识:伪元素)。该方法同样也返回一个CSSStyleDeclaration对象(与style属性的类型相同),我们可以根据这个对象获得计算后的样式信息。
<!DOCTYPE html><html><head>    <title>Computed Styles Example</title>    <style type="text/css">        #myDiv {            background-color: blue;            width: 100px;            height: 200px;        }    </style>    <script type="text/javascript">        function showComputedStyles(){            var myDiv = document.getElementById("myDiv");            var computedStyle = document.defaultView.getComputedStyle(myDiv, null);            //前者Chrome 后者IE9            console.log(computedStyle.backgroundColor);   //"rgb(255, 0, 0)"            console.log(computedStyle.width);             //"99.9844px" "100px"            console.log(computedStyle.height);            //"199.992px" "200px"            console.log(computedStyle.border);            //"1.5px solid rgb(0, 0, 0)" ""            console.log(computedStyle.borderLeftWidth);   //"1.5px" "1px"            console.log(computedStyle.visibility);    //visible            console.log(computedStyle.float);    //none undefined        }    </script></head><body>    <div id="myDiv" style="background-color: red; border: 1px solid black"></div>    <input type="button" value="Show Computed Styles" onclick="showComputedStyles()">    <p>(This example won't work in IE &lt; 9.)</p></body></html>
  • 结果非常地怪异,真是难以理解。在Chrome中怎么蹦出了一个小数(后来过了几天我又试了一下,结果居然正确了(不再显示小数),我这几天刚刚更新了Chrome的版本,难道是最近刚刚修复了这个bug?)?IE9中的border属性怎么没有了?也许以后我可能会知道,但是我现在的确想不出来。不过总的来说有两点,1是会得到该元素最终的样式信息对象(重写会覆盖)。2是没有设置的属性会有默认值(比如float属性,虽然IE中出现了undefined,但是Chrome中是none)
  • 更神奇的是,书上居然说IE不支持getComputedStyle()方法(应该是笔误,是指IE8-不支持,也有可能是因为我看的是盗版的书)。
    //替换上面例子中的方法    function showComputedStyles(){        var myDiv = document.getElementById("myDiv");        //IE 中支持currentStyle属性,返回一个CSSStyleDeclaration实例        var computedStyle = myDiv.currentStyle;        alert(computedStyle.backgroundColor);   //"red"        alert(computedStyle.width);             //"100px"        alert(computedStyle.height);            //"200px"        //IE 不返会border样式,因为这个是一个综合属性(主要看浏览器心情)        //border指定了border-left-width、border-top-width等等属性        alert(computedStyle.border);            //undefined IE8之前        alert(computedStyle.border == "");      //IE9之后变成了空字符串        alert(computedStyle.borderLeftWidth);   //"1px"    }

操作样式表

  • CSSStyleSheet 类型表示的是样式表,包括通过<link>元素包含的样式表和在<style>元素中定义的样式表,这两个元素本身是由HTMLLinkElementHTMLStyleElement类型表示的。CSSStyleSheet类型只表示样式表,而不管这些样式表在HTML中是如何定义的。HTMLLinkElementHTMLStyleElement类型是允许修改HTML特性,但CSSStyleSheet对象则是一套只读的接口(有一个属性disabled除外)。使用下面的代码可以确定浏览器是否支持DOM 2级样式表
    var supportsDOM2StyleSheet = document.implementation.hasFeature("StyleSheets", "2.0");
  • CSSStyleSheet继承自StyleSheet。从StyleSheet接口继承而来的属性如下:
    1. disabled:表示样式表是否禁用(可读写)。设置为true可以禁用样式表。
    2. href:如果样式表是通过<link>元素包含的,则是样式表的URL,否则是null。
    3. media:当前样式表支持的所有媒体类型的集合。这个集合也有length属性和item()方法,也可以通过方括号语法取得集合中的项。如果集合是空列表,表示适用于所有媒体。在IE中,media是一个反映<link><style>元素中media特性的字符串。
    4. ownerNode:指向拥有当前样式表的节点的指针(一般是<link><style>元素节点)。如果样式表是其他样式表通过@import导入的,则这个值为null。IE不支持该属性。
    5. parentStyleSheet:如果当前样式表是通过@import导入的,则这个属性指向导入它的样式表的指针。
    6. title:title属性的值。
    7. type:表示样式表类型的字符串。对CSS样式表而言,这个字符串是”type/css”。
  • 上面都是继承而来的属性和方法,另外CSSStyleSheet类型还支持以下属性和方法:
    1. cssRules:样式表包含的样式规则的集合。IE8-不支持这个属性,但IE都有一个类似的rules属性。
    2. ownerRule:如果样式表是@import导入的,这个属性就是一个指针,指向表示导入的规则;否则为null。IE8-不支持这个属性。
    3. deleteRule(index):删除cssRules集合中指定位置的规则。IE8-不支持这个方法,但IE都支持一个类似的removeRule(index)。
    4. insertRule(rule, index):向cssRules集合中指定的位置插入rule字符串。IE8-不支持这个方法,但IE都支持一个类似的addRule()方法。
  • 应用于文档的所有样式表是通过document.styleSheets集合表示的。同样也有length和item()。
<!DOCTYPE html><html><head>    <title>Style Sheets Example</title>    <link rel="stylesheet" title="blah" type="text/css" href="stylesheet1.css">    <!--不同浏览器的document.styleSheets返回的样式表有所不同,所有浏览器都会返回rel特性为"stylesheet"的样式表    而IE和Opera(我的Chrome也行,其他没求证过)也包含rel特性为"alternate stylesheet"的样式表-->    <link rel="alternate stylesheet" type="text/css" href="stylesheet2.css">        <style type="text/css">        #myDiv {            background-color: blue;            width: 100px;            height: 200px;        }    </style>    <script type="text/javascript">        function outputStyleSheets(){            var sheet = null;            //这里再强调一下,不使用len而直接写在'i<'后面会影响效率,且如果函数体中包含影响length属性的代码,会出现错误。            for (var i=0, len=document.styleSheets.length; i < len; i++){                sheet = document.styleSheets[i];                alert(sheet.href);//style元素返回null IE8- style元素返回""            }        }        function toggleStyleSheet(){            /*body {                background-color: silver;            }*/            //点击可以禁用/启用样式,立即改变背景颜色。            document.styleSheets[0].disabled = !document.styleSheets[0].disabled;        }    </script></head><body>    <div id="myDiv"></div>    <input type="button" value="Output Style Sheets" onclick="outputStyleSheets()">    <input type="button" value="Enable/Disable Style Sheet" onclick="toggleStyleSheet()"></body></html>
  • 也可以直接通过元素节点的sheet属性获得CSSStyleSheet对象。IE8-不支持该属性,IE8-仅支持styleSheet属性。IE9+后两个属性都支持。
    function getStyleSheet(element){        return element.sheet || element.styleSheet;    }    var link = document.getElementsByTagName("link")[0];    var sheet = getStyleSheet(link);    console.log(sheet.href);    console.log(sheet.media);//MediaList    console.log(sheet.ownerNode == link); //true    console.log(sheet.title);//例子中是blah 不设就是null    console.log(sheet.type);//text/css    console.log(sheet.cssRules);//CSSRuleList    console.log(sheet.cssRules[0].cssText);//body { background-color: silver; }
  • 下面是一个关于CSSRule的例子:
    function getCssRule(sheet){        return sheet.cssRules || sheet.rules;    }    var link = document.getElementsByTagName("link")[0];    var sheet = getStyleSheet(link);    var cssRuleList = getCssRule(sheet);    console.log(cssRuleList[0].cssText);//body { background-color: silver; }  IE8- undefined 下面会介绍这个cssText属性    console.log(sheet.ownerRule);//null IE8- undefined    var stylerule = "body { border-color: red;border-style: ridge;}";    if (typeof sheet.insertRule == "function") {        sheet.insertRule(stylerule, 0);//IE9+    } else {        sheet.addRule("body", "border-color: red; border-style: ridge;", 0);//IE都支持    }    console.log(cssRuleList[0].cssText);//body { border-color: red; border-style: ridge; }    if (typeof sheet.deleteRule == "function") {        sheet.deleteRule(1);//IE9+    } else {        sheet.removeRule(1);//IE都支持    }

CSSRule

  • CSSRule对象表示样式表中的每一条规则(比如body{…}就是一条规则)。实际上,CSSRule是一个供其他类型继承的基类型,其中最常见的就是CSSStyleRule类型,表示样式信息。CSSStyleRule类型包含以下属性:
    1. cssText:返回整条规则对应的文本。书上老说IE不支持,我发现IE9+都支持的。而不同浏览器的返回值可能有小区别(大小写)。
    2. parentRule:如果当前规则是导入规则,这个属性引用的就是导入规则;否则这个值为null。
    3. parentStyleSheet:当前规则所属的样式表。
    4. selectorText:返回当前规则的选择符文本(比如body)。Opera允许修改该属性,其余浏览器该属性只读。
    5. style:一个CSSStyleDeclaration对象(刚开始已经详细介绍过了),可以通过它设置和取得规则中特定的样式值。
    6. type:表示规则类型的常量值。对于样式规则,这个值是1。
  • 其中最常用的属性是cssText、selectorText和style。cssText属性与style.cssText属性类型。但前者包含选择符和花括号,后者只有花括号里面的内容。此外cssText是只读的,而style.cssText可以被重写。
<!DOCTYPE html><html><head>    <title>CSS Rules Example</title>    <style type="text/css">        div.box {            background-color: blue;            width: 100px;            height: 200px;        }    </style>    <script type="text/javascript">        function getStyleInfo(){            var sheet = document.styleSheets[0];            var rules = sheet.cssRules || sheet.rules;//后者适用于IE8-            var rule = rules[0];            alert(rule.selectorText);//div.box            alert(rule.cssText);//div.box{...}            rule.cssText = "div.box { background-color: red;  width: 100px;  height: 200px; }";            alert(rule.cssText);//不变,说明上一句代码无效(cssText只读不可写 Writable为false?)            var cssText = Object.getOwnPropertyDescriptor(rule, "cssText");//undefined 也许DOM对象不能这么用?            //alert(cssText.writable);            alert(rule.style.cssText);//div.box{...}中的...            alert(rule.style.backgroundColor);//blue            alert(rule.style.width);//100px            alert(rule.style.height);//200px        }        //可以使用下列方式重写样式规则        function changeStyleInfo(){                    var sheet = document.styleSheets[0];            var rules = sheet.cssRules || sheet.rules;            var rule = rules[0];                rule.style.backgroundColor = "red";        }    </script></head><body>    <div class="box" style="margin-bottom: 10px"></div>    <div class="box"></div>    <input type="button" value="Get Style Info" onclick="getStyleInfo()">    <input type="button" value="Change Style Info" onclick="changeStyleInfo()"></body></html>

创建规则

  • 其实这个前面已经提到过了。使用insertRule(rule, index);可以样式表中添加新规则。而IE8-只支持addRule(selectorText, cssText, index);(据说这个方法最多创建上限4095条)

删除规则

  • 这个前面也提到过了,使用deleteRule(index);IE8-只支持removeRule(index)

元素大小

  • DOM中没有规定如何确定页面的大小。IE 率先引入了一些属性,目前所有主流浏览器都已经支持这些属性。

偏移量

  • 首先要介绍的是偏移量(offset dimension),包括元素在屏幕上占用的所有可见的空间。元素的可见大小由其高度宽度决定,包括所有内边距滚动条边框大小(不包括外边距)。通过下面四个属性可以取得元素的偏移量。
    1. offsetHeight:元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、(可见的)水平滚动条的高度、上边框高度和下边框高度。
    2. offsetWidth:元素在水平方向上占用的空间大小,以像素计。包括元素的宽度、(可见的)垂直滚动条的宽度、左边框和右边框宽度。
    3. offsetLeft:元素的左外边框至包含元素的左内边框的像素距离。
    4. offsetTop:元素的上外边框至包含元素的上内边框的像素距离。
  • 其中offsetLeft和offsetTop和包含元素有关,包含元素的引用保存在offsetParent属性中。offsetParent不一定与parentNode的值相等。例如<td>元素的offsetParent则是<table>元素,因为<table>元素是DOM层次中距离<td>最近的一个具有大小的元素。
    这里写图片描述

  • 如果想要知道某个元素在页面上的偏移量,只要将这个元素的offsetLeft和offsetTop与其offsetParent的相同属性相加,直至到根元素为止,就可以得到一个准确的值。

    function getElementLeft(element){        var actualLeft = element.offsetLeft;        var current = element.offsetParent;        while (current !== null){            actualLeft += current.offsetLeft;            current = current.offsetParent;        }        return actualLeft;    }    //top同理
  • 要注意这4个属性是只读的。并且每次访问他们都需要重新计算(至于为什么访问值也会计算,想想访问器属性就知道了)。应该尽量避免重复访问这些属性。如果需要重复使用,可以保存在局部变量中,不过要在距离不会修改的前提下。

客户区大小

  • clientWidth和clientHeight属性表示的是元素内容及内边距的长和宽。
    这里写图片描述
  • 获得页面视口大小,可以通过document.documentElement(即文档节点)的clientWidth和clientHeight属性。IE7之前的版本中得使用document.body的这两个属性去获取。
    <!--注意要写在body内部,如果写在head里面document.body为null-->    <script>        console.log(document.documentElement.clientWidth);//杂项下为0 其余正常 但是都有区别        console.log(document.body.clientWidth);//都是正常数字,但是都有区别    </script>
  • 这两个属性也是只读的,每次访问都会重新计算。

滚动大小

  • 最后介绍的是滚动大小(scroll dimension),指的是包含滚动内容的元素的大小。有些元素(例如<html>元素)即使没有执行任何代码也能自动地添加滚动条。有些元素则需要设置CSS的overflow属性才能滚动,下面是关于滚动大小的4个属性:
    1. scrollHeight:在没有滚动条的情况下,元素内容的总高度。
    2. scrollWidth:在没有滚动条的情况下,内容的总宽度。
    3. scrollLeft:被隐藏在内容区域左侧的像素数,通过设置这个属性可以改变元素的滚动位置。
    4. scrollTop:同理,被隐藏在内容区域上册的像素数,通过设置这个属性可以改变元素的滚动位置。
      这里写图片描述
  • scrollHeight和scrollWidth主要用于确定元素内容的实际大小。例如带有垂直滚动条的页面总高度为document.documentElement.scrollHeight。(在IE7之前为document.body.scrollHeight,因为IE7以前的版本将body元素视为浏览器的视口中的元素)
<!DOCTYPE html><html><head>    <title>Offset Dimensions Example</title>    <meta charset="utf-8">    <style>        .test {            width: 500px;height:500px;overflow: auto        }        .test div{            width: 1000px;height:800px;            background-color: red;        }    </style></head><body>    <div class="test">        <div>1</div>    </div>    <button onclick="totop()">回到顶部</button>    <button onclick="tobottom()">回到底部</button>    <button onclick="show()">显示信息</button>    <button onclick="showWindow()">显示页面信息</button>    <script>        var div = document.getElementsByClassName("test")[0];        function totop() {            div.scrollTop = 0;        }        function tobottom() {            div.scrollTop = div.scrollHeight - div.clientHeight;        }        function show() {            alert(div.scrollWidth);            alert(div.scrollHeight);            alert(div.scrollLeft);            alert(div.scrollTop);        }        function showWindow() {            //以下结果为Chrome测试结果            //第一个539是body的高度,而768则是整个页面的高度。当我用调试窗口显示在浏览器下方时,clientHeight会变小            //但是scrollHeight没有发生变化            alert(document.documentElement.scrollWidth);//1440            alert(document.documentElement.scrollHeight);//539             alert(document.documentElement.clientWidth);//1440            alert(document.documentElement.clientHeight);//768        }    </script></body></html>
  • 而对于不包含滚动条的页面,scrollWidth、scrollHeight、clientWidth和clientHeight之间的关系并不十分清晰。我们对同一个页面获取document.documentElement的这些属性,见上面的showWindow()函数。

确定元素大小

  • 主流浏览器为每个元素提供了getBoundingClientRect()方法。这个方法会返回一个矩形对象,包含4个属性:left、top、right、bottom。这个属性给出了元素在页面中相对于视口的位置。IE8及更早版本认为文档的左上角左边是(2,2),而其他浏览器包括IE9则认为是(0,0),可以通过下面的函数:
    //"use strict";    //var getBoundingClientRect = function fname(element) {    function getBoundingClientRect(element){        var scrollTop = document.documentElement.scrollTop;        var scrollLeft = document.documentElement.scrollLeft;        if (element.getBoundingClientRect){            //if (typeof fname.offset != "number"){            if (typeof arguments.callee.offset != "number"){                var temp = document.createElement("div");                temp.style.cssText = "position:absolute;left:0;top:0;";                document.body.appendChild(temp);                //fname.offset = -temp.getBoundingClientRect().top - scrollTop;                arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop;                document.body.removeChild(temp);                temp = null;            }            var rect = element.getBoundingClientRect();            //var offset = fname.offset;            var offset = arguments.callee.offset;            return {                left: rect.left + offset,                right: rect.right + offset,                top: rect.top + offset,                bottom: rect.bottom + offset            };        } else {//如果不支持getBoundingClientRect()方法            //这两个方法在前面提到过通过while将offsetLeft累加获得            var actualLeft = getElementLeft(element);            var actualTop = getElementTop(element);           return {                left: actualLeft - scrollLeft,                right: actualLeft + element.offsetWidth - scrollLeft,                top: actualTop - scrollTop,                bottom: actualTop + element.offsetHeight - scrollTop            }        }    }
  • 上面的这个方法创建了一个div元素并获取它的坐标信息。然后将offset保存在该方法中,下次调用则直接使用offset变量。
  • 注意到上面用到了arguments.callee属性,该属性在严格模式下是不能使用的。我们可以使用命名函数表达式的写法去完成(直接写成getBoundingClientRect耦合性太高)。
0 0
原创粉丝点击