JS高级程序设计——第12章 DOM2和DOM3 12.2 样式

一、访问元素的样式

1、定义样式的方式
  1. 在 HTML 中定义样式的方式有 3 种:通过<link/>元素包含外部样式表文件、使用<style/>元素定义嵌入式样式,以及使用 style 特性定义针对特定元素的样式。
  2. DOM2 级样式”模块围绕这 3 种应用 样式的机制提供了一套 API要确定浏览器是否支持 DOM2 级定义的 CSS 能力,可以使用下列代码。
var supportsDOM2CSS = document.implementation.hasFeature("CSS", "2.0"); 
var supportsDOM2CSS2 = document.implementation.hasFeature("CSS2", "2.0");
  1. 对于使用短划线(分隔不同的词汇,例如 background-image)的 CSS 属性名,必须将其转换成驼峰大小写形式,才能通过 JavaScript 来访问。
    在这里插入图片描述
  • 特殊:多数情况下,都可以通过简单地转换属性名的格式来实现转换。其中一个不能直接转换的 CSS 属性 就是 float。由于 float 是 JavaScript 中的保留字,因此不能用作属性名“DOM2 级样式”规范规定 样式对象上相应的属性名应该是 cssFloat;Firefox、Safari、Opera 和 Chrome 都支持这个属性,而 IE 支持的则是 styleFloat
  • 几个例子:
    只要取得一个有效的 DOM 元素的引用,就可以随时使用 JavaScript 为其设置样式。
var myDiv = document.getElementById("myDiv");
//设置背景颜色 
myDiv.style.backgroundColor = "red";
//改变大小
myDiv.style.width = "100px"; myDiv.style.height = "200px";
//指定边框
myDiv.style.border = "1px solid black";

在以这种方式改变样式时,元素的外观会自动被更新。

在标准模式下,所有度量值都必须指定一个度量单位。在混杂模式下,可以将 style.width 设置为"20",浏览器会假设它是"20px";但在标准模式下,将 style.width 设置为"20"会导致被忽略——因为没有度量单位。在实践中,最好始 终都指定度量单位。

  • 通过 style 对象同样可以取得在 style 特性中指定的样式。以下面的 HTML 代码为例。
<div id="myDiv" style="background-color:blue; width:10px; height:25px"></div>

在 style 特性中指定的样式信息可以通过下列代码取得。

alert(myDiv.style.backgroundColor);//"blue"
alert(myDiv.style.width);//"10px"
alert(myDiv.style.height);//"25px"

如果没有为元素设置 style 特性,那么 style 对象中可能会包含一些默认的值,但这些值并不能准确地反映该元素的样式信息

2、DOM样式属性和方法
  1. style 对象的一些属性和方法

    DOM2 级样式”规范还为 style 对象定义了一些属性和方法。这些属性和方法在提供元素的 style特性值的同时,也可以修改样式。下面列出了这些属性和方法。

    cssText:如前所述,通过它能够访问到 style 特性中的 CSS 代码。
    length:应用给元素的 CSS 属性的数量。
    parentRule:表示 CSS 信息的 CSSRule 对象。本节后面将讨论 CSSRule 类型。
    getPropertyCSSValue(propertyName):返回包含给定属性值的 CSSValue 对象。
    getPropertyPriority(propertyName):如果给定的属性使用了**!important** 设置,则返回"important";否则,返回空字符串
    getPropertyValue(propertyName):返回给定
    属性的字符串值

    item(index):返回给定位置的 CSS 属性的名称
    removeProperty(propertyName):从样式中删除给定属性
    setProperty(propertyName,value,priority):将给定属性设置为相应的值,并加上优先权标志("important"或者一个空字符串)。

  2. 例子

  • 通过 cssText 属性可以访问 style 特性中的 CSS 代码
    在读取模式下,cssText 返回浏览器对 style特性中 CSS 代码的内部表示。
    在写入模式下,赋给 cssText 的值会重写整个 style 特性的值;也就是说,以前通过 style 特性指定的样式信息都将丢失。下面是使用 cssText 属性的 一个例子。(与外部样式表和内嵌样式无关)
myDiv.style.cssText = "width: 25px; height: 100px; background-color: green"; 
alert(myDiv.style.cssText);
  • 设计 length 属性的目的,就是将其与 item()方法配套使用,以便迭代在元素中定义的 CSS 属性。 在使用 length 和 item()时,style 对象实际上就相当于一个集合,都可以使用**方括号语法来代替 item()**来取得给定位置的 CSS 属性,如下面的例子所示。
for (var i=0, len=myDiv.style.length; i < len; i++){ 
	alert(myDiv.style[i]); //或者myDiv.style.item(i)
}

无论是使用方括号语法还是使用 item()方法,都可以取得 CSS 属性名****(“background-color”, 不是"backgroundColor")。

  • 然后,就可以在 getPropertyValue()中使用取得的属性名进一步取得属性的值,getPropertyValue()方法取得的始终都是 CSS 属性值的字符串表示,如下所示。
var prop, value, i, len;
for (i=0, len=myDiv.style.length; i < len; i++){
	prop = myDiv.style[i]; //或者 myDiv.style.item(i) 
	value = myDiv.style.getPropertyValue(prop);
	 alert(prop + " : " + value);
}
  • 如果你需要更多信息,可以使用 getPropertyCSSValue()方法(已弃用),它返回一个包含两个属性的 CSSValue 对象,这两个属性分别是:cssText 和 cssValueType

    其中,cssText 属性的值与 getPropertyValue()返回的值相同而 cssValueType 属性则是一个数值常量,表示值的类型:0 表示继承的值,1 表示基本的值,2 表示值列表,3 表示自定义的值。

    以下代码既输出 CSS 属性值,也输出值的类型。

var prop, value, i, len;
for (i=0, len=myDiv.style.length; i < len; i++){
prop = myDiv.style[i]; //或者myDiv.style.item(i)
value = myDiv.style.getPropertyCSSValue(prop);
alert(prop + " : " + value.cssText + " (" + value.cssValueType + ")");
}
  • 要从元素的样式中移除某个 CSS 属性,需要使用 removeProperty()方法。使用这个方法移除一个属性,意味着将会为该属性应用默认的样式(从其他样式表经层叠而来)。例如,要移除通过 style 特性设置的 border 属性,可以使用下面的代码。
myDiv.style.removeProperty("border");

不确定某个给定的 CSS 属性拥有什么默认值的情况下,就可以使用这个方法。只要移除相应的属性,就可以为元素应用默认值

3、计算的样式

虽然 style 对象能够提供支持 style 特性的任何元素的样式信息,但它不包含那些从其他样式表 层叠而来并影响到当前元素的样式信息

  1. getComputedStyle()方法:“DOM2 级样式”增强了 document.defaultView,提供了 getComputedStyle()方法。
  • 这个方法接受两个参数要取得计算样式的元素一个伪元素字符串(例 如":after")。如果不需要伪元素信息,第二个参数可以是 null。
  • getComputedStyle()方法返回一个 CSSStyleDeclaration 对象(与 style 属性的类型相同),其中包含当前元素的所有计算的样式。 以下面这个 HTML 页面为例。
    在这里插入图片描述
    以下代码可以取得这个元素计算后的样式。
    在这里插入图片描述
    ⚠️注意:边框属性可能会也可能不会返回样式表中实际的 border 规则(Opera 会返回,但其他浏览器不会)。存在这个差别的原因是不同浏览器解释综合(rollup)属性(如 border)的方式不同,因为设置这种属性实际上会涉及很多其他属性。在设置 border 时,实际上是设置了四个边的边框宽度、颜色、样式属性
    ( border-left-width 、 border-top-color 、 border-bottom-style , 等 等 )
    。 因 此 , 即 使 computedStyle.border 不会在所有浏览器中都返回值,但 computedStyle.borderLeftWidth 会返回值。
    因此,在使用 getComputedStyle()方法时,最好多在几种浏览器中测试一下
  1. currentStyle 属性IE 不支持 getComputedStyle()方法,但它有一种类似的概念。在 IE 中,每个具有 style 属性的元素还有一个 currentStyle 属性。这个属性是 CSSStyleDeclaration 的实例,包含当前元素全 部计算后的样式。取得这些样式的方式也差不多,如下面的例子所示。
    在这里插入图片描述
  • 无论在哪个浏览器中,最重要的一条是要记住所有计算的样式都是只读的;不能修改计算后样式对 象中的 CSS属性
  • 不能指望某个 CSS 属性的默认值在不同浏览器中是相同的。如果你需要元素具有某个特定的默认值,应该手工在样式表中指定该值

二、操作样式表

1、样式表类型及属性
  1. 样式表类型:CSSStyleSheet 类型表示的是样式表,包括通过<link>元素包含的样式表和在<style>元素中定义 的样式表。CSSStyleSheet 对象是一套只读的接口(有一个属性例外)。
  • 使用下面的代码可以确定浏览器是否支持 DOM2 级样式表
var supportsDOM2StyleSheets = document.implementation.hasFeature("StyleSheets", "2.0");
  1. CSSStyleSheet 继承自 StyleSheet,后者可以作为一个基础接口来定义非 CSS 样式表。从 StyleSheet 接口继承而来的属性如下。
    在这里插入图片描述
  2. document.styleSheets 集合:应用于文档的所有样式表是通过document.styleSheets 集合来表示的。通过这个集合的 length属性可以获知文档中样式表的数量,而通过方括号语法或 **item()**方法可以访问每一个样式表。来看一个例子。
var sheet = null;
for (var i=0, len=document.styleSheets.length; i < len; i++){
	sheet = document.styleSheets[i];
    alert(sheet.href);
}

以上代码可以输出文档中使用的每一个样式表的 href 属性(

  • 不同浏览器的 document.styleSheets 返回的样式表也不同。所有浏览器都会包含<style>元素 和 rel 特性被设置为"stylesheet"的<link>元素引入的样式表。IE 和 Opera 也包含 **rel 特性被设置 为"alternate stylesheet"**的<link>元素引入的样式表。
  1. 也可以直接通过<link><style>元素取得 CSSStyleSheet 对象。DOM 规定了一个包含CSSStyleSheet 对象的属性,名叫 sheet;除了 IE,其他浏览器都支持这个属性。IE 支持的是 styleSheet 属性。要想在不同浏览器中都能取得样式表对象,可以使用下列代码。
    在这里插入图片描述
    这里的 getStyleSheet()返回的样式表对象与 document.styleSheets 集合中的样式表对象相同。(一个是对象,一个是对象集合)
2、css规则
  1. CSSRule 对象
    • CSSRule 对象表示样式表中的每一条规则。实际上,CSSRule 是一个供其他多种类型继承的基类型,其中最常见的就是 CSSStyleRule 类型,表示样式信息(其他规则还有@import、@font-face、 @page 和@charset,但这些规则很少有必要通过脚本来访问)。
  2. CSSStyleRule 对象包含下列属性
    在这里插入图片描述
  • 其中三个最常用的属性是 cssTextselectorTextstylecssText 属性style.cssText 属性类似,但并不相同。前者包含选择符文本和围绕样式信息的花括号,后者只包含样式信息(类似于 元素的 style.cssText)。此外,cssText 是只读的,而 style.cssText 也可以被重写

  • 大多数情况下,仅使用 style 属性就可以满足所有操作样式规则的需求了这个对象就像每个元素上的 style 属性一样,可以通过它读取和修改规则中的样式信息。以下面的 CSS 规则为例。【这就是一条css规则】
    在这里插入图片描述
    假设这条规则位于页面中的第一个样式表中,而且这个样式表中只有这一条样式规则,那么通过下列代码可以取得这条规则的各种信息。
    在这里插入图片描述
    使用这种方式,可以像确定元素的行内样式信息一样,确定与规则相关的样式信息。与使用元素的方式一样,在这种方式下也可以修改样式信息,如下面的例子所示。
    在这里插入图片描述
    必须要注意的是,以这种方式修改规则会影响页面中适用于该规则的所有元素。(修改样式表样式了,所有使用这个样式规则的元素当然都会改变了)

3、创建规则
  1. insertRule()方法: DOM 规定,要向现有样式表中添加新规则,需要使用 insertRule()方法。这个方法接受两个参数:规则文本和表示在哪里插入规则的索引。下面是一个例子。

    sheet.insertRule("body { background-color: silver }", 0); //DOM 方法
    

    插入的规则将成为样式表中的第一条规则(插入到了 位置 0)。Firefox、Safari、Opera 和 Chrome 都支持 insertRule()方法。

  2. addRule()方法:E8 及更早版本支持一个与 insertRule()方法类似的方法,名叫 addRule(),也接收两必选参数:选择符文本和 CSS 样式信息一个可选参数:插入规则的位置。在 IE 中插入与前面例子相同的规则,可使用如下代码。

    sheet.addRule("body", "background-color: silver", 0); 
    //仅对 IE 有效
    

    有关这个方法的规定中说,最多可以使用 addRule()添加 4095 条样式规则。超出这个上限的调用 将会导致错误。

  3. 以跨浏览器的方式向样式表中插入规则,可以使用下面的函数。这个函数接受 4 个参数:要向其中添加规则的样式表以及与 addRule()相同的 3 个参数,如下所示。
    在这里插入图片描述

  • 下面是调用这个函数的示例代码。

    insertRule(document.styleSheets[0], "body", "background-color: silver", 0);
    

虽然可以像这样来添加规则,但随着要添加规则的增多,这种方法就会变得非常繁琐。因此,如果要添加的规则非常多,我们建议还是采用第 10 章介绍过的动态加载样式表的技术

4、删除规则
  1. deleteRule()方法:从样式表中删除规则的方法是 deleteRule(),这个方法接受一个参数:要删除的规则的位置。例如,要删除样式表中的第一条规则,可以使用以下代码。
sheet.deleteRule(0); //DOM 方法
  1. removeRule()方法:IE 支持的类似方法叫 removeRule(),使用方法相同,如下所示:
sheet.removeRule(0); //仅对 IE 有效
  1. 下面是一个能够跨浏览器删除规则的函数。第一个参数是要操作的样式表,第二个参数是要删除的规则的索引

    function deleteRule(sheet, index){
        if (sheet.deleteRule){
            sheet.deleteRule(index);
        } else if (sheet.removeRule){
            sheet.removeRule(index);
        }
    }
    
    

    调用这个函数的方式如下。

    deleteRule(document.styleSheets[0], 0);
    

与添加规则相似,删除规则也不是实际 Web 开发中常见的做法。考虑到删除规则可能会影响 CSS 层叠的效果,因此请大家慎重使用。

三、元素大小

1、偏移量
  1. 偏移量:包括元素在屏幕上占用的所有可见的空间。(几个数值)
  2. 元素的可见大小由其高度、宽度决定,包括所有内边距滚动条边框大小(注意,不包括外边距)。通过 下列 4 个属性可以取得元素的偏移量。
    在这里插入图片描述
  • offsetParent 属性:其中,offsetLeft 和 offsetTop 属性与包含元素有关包含元素的引用保存在 offsetParent 属性中offsetParent 属性不一定与 parentNode 的值相等(parentNode指向上一层父节点)。例如,<td>元素的 offsetParent 是作为其祖先元素的<table>元素,因为<table>是在 DOM 层次中距<td>最近的一个具有大小的元素

图 12-1 形象地展示了上面几个属性表示的不同大小。
在这里插入图片描述

  1. 要想知道某个元素在页面上的偏移量将这个元素的 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;
 }
  • 取得元素的上偏移量
function getElementTop(element){
    var actualTop = element.offsetTop;
    var current = element.offsetParent;
    while (current !== null){
        actualTop += current. offsetTop;
        current = current.offsetParent;
	}
    return actualTop;
}

这两个函数利用 offsetParent 属性在 DOM 层次中逐级向上回溯,将每个层次中的偏移量属性合计到一块。对于简单的 CSS 布局的页面,这两函数可以得到非常精确的结果。对于使用表格和内嵌框架布局的页面,由于不同浏览器实现这些元素的方式不同,因此得到的值就不太精确了

所有这些偏移量属性都是只读的,而且每次访问它们都需要重新计算。因此,应该尽量避免重复访问这些属性;如果需要重复使用其中某些属性的值,可以将它们保存在局部变量中,以提高性能。

2、客户区大小
  1. 元素的客户区大小(client dimension),指的是元素内容及其内边距所占据的空间大小。【与元素的可见大小不同。元素的客户区大小 = 元素内容 + 内边距;元素的可见大小 = 元素内容 + 内边距 + 边框 + 滚动条】
  2. 有关客户区大小的属性有两个clientWidthclientHeight
    其中,clientWidth 属性 = 元素内容区宽度 + 左右内边距宽度;
    clientHeight 属性是 = 元素内容区高度 + 上下内边距高度。图 12-2 形象地说明 了这些属性表示的大小。
    在这里插入图片描述
  3. 如下面的例子所示,要确定浏览器视口大小(浏览器窗口的尺寸不包括工具栏和滚动条),可以使用 document.documentElement 或 document.body(在 IE7 之前的版本中)的 clientWidth 和 clientHeight。
function getViewport(){
    if (document.compatMode == "BackCompat"){
    //这个函数首先检查 document.compatMode 属性,以确定浏览器是否运行在混杂模式。
        return {
            width: document.body.clientWidth,
            height: document.body.clientHeight
		};
	} else {
        return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight
		}; 
	}
}

这个函数会返回一个对象,包含两个属性:width 和 height;表示浏览器视口(<html><body>元素)的大小。

  1. 客户区大小也是只读的,也是每次访问都要重新计算的。
3、滚动大小
  1. 滚动大小(scroll dimension):指的是包含滚动内容的元素的大小。有些元素(例如 <html>元素),即使没有执行任何代码也能自动地添加滚动条;但另外一些元素,则需要通过 CSS 的 overflow 属性进行设置才能滚动。
  2. 以下是 4 个与滚动大小相关的属性。
    在这里插入图片描述
    下图展示了这些属性代表的大小。
    在这里插入图片描述
  • scrollWidthscrollHeight 主要用于确定元素内容的实际大小。例如,通常认为<html>元素是在 Web 浏览器的视口中滚动的元素(IE6 之前版本运行在混杂模式下时是<body>元素)。因此,带有垂直滚动条的页面总高度就是 document.documentElement.scrollHeight。

  • 对于不包含滚动条的页面而言scrollWidth 和 scrollHeight 与 clientWidth 和 clientHeight 之间的关系并不十分清晰。在这种情况下,基于 document.documentElement 查看这些属性会在不同浏览器间发现一些不一致性问题,如下所述。

     Firefox 中这两组属性始终都是相等的,但大小代表的是文档内容区域的实际尺寸,而非视口的尺寸

     Opera、Safari 3.1 及更高版本、Chrome 中的这两组属性是有差别的,其中 scrollWidth 和 scrollHeight 等于视口大小,而 clientWidth 和 clientHeight 等于文档内容区域的大小。

     IE(在标准模式)中的这两组属性不相等,其中 scrollWidth 和 scrollHeight 等于文档内容区域的大小,而 clientWidth 和 clientHeight 等于视口大小

  1. 确定文档的总高度时(包括基于视口的最小高度时),必须取得 scrollWidth/clientWidth 和 scrollHeight/clientHeight 中的最大值,才能保证在跨浏览器的环境下得到精确的结果。下面就 是这样一个例子。
var docHeight = Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight);
var docWidth = Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth);
//注意,对于运行在混杂模式下的 IE,则需要用 document.body 代替 document.documentElement。
  1. 通过 scrollLeftscrollTop 属性既可以确定元素当前滚动的状态,也可以设置元素的滚动位置。将元素的 scrollLeft 和 scrollTop 设置为 0,就可以重置元素的滚动位置。下面这个函数会检测元素是否位于顶部,如果不是就将其回滚到顶部。
 function scrollToTop(element){
        if (element.scrollTop != 0){
            element.scrollTop = 0;
        }
}
4、确定元素大小
  1. getBoundingClientRect()方法:IE、Firefox 3+、Safari 4+、Opera 9.5 及 Chrome 为每个元素都提供了一个 getBoundingClientRect()方法。这个方法返回会一个矩形对象
  2. 包含 4 个属性:left、top、right 和 bottom。这些属性给出了元素在页面中相对于视口的位置。但是浏览器的实现稍有不同。
  • IE8 及更早版本认为文档的左上角坐标是(2, 2),而其他浏览器包括 IE9 则将传统的(0,0)作为起点坐标。因此,就需要在一开始检查一下位于 (0,0)处的元素的位置,在 IE8 及更早版本中,会返回(2,2),而在其他浏览器中会返回(0,0)。来看下面的函数:
    在这里插入图片描述
    这个函数使用了它自身的属性(offset属性)来确定是否要对坐标进行调整
    第一步是检测属性是否有定义,如果没有就定义一个。最终的 offset 会被设置为新元素上坐标的负值,实际上就是在 IE 中设置为2,在 Firefox 和 Opera 中设置为0。

为此,需要创建一个临时的元素,将其位置设置在(0,0),然后再调用其 getBoundingClientRect()。而之所以要减去视口的 scrollTop,是为了防止调用这个函数时窗口被滚动了。这样编写代码,就无需每次调用这个函数都执行两次 getBoundingClientRect()了。接 下来,再在传入的元素上调用这个方法并基于新的计算公式创建一个对象。

  • 对于不支持 getBoundingClientRect()的浏览器,可以通过其他手段取得相同的信息。一般来说,right 和 left 的差值与 offsetWidth 的值相等,而 bottom 和 top 的差值与 offsetHeight 相等。而且,left 和 top 属性大致等于使用本章前面定义的 getElementLeft()和 getElementTop() 函数取得的值。综合上述,就可以创建出下面这个跨浏览器的函数:
function getBoundingClientRect(element){
    var scrollTop = document.documentElement.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft;
    if (element.getBoundingClientRect){
       	if (typeof arguments.callee.offset != "number"){
			var temp = document.createElement("div");
			temp.style.cssText = "position:absolute;left:0;top:0;"; 
			document.body.appendChild(temp);
			arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop; 		
			document.body.removeChild(temp);	
			temp = null;
		}
		var rect = element.getBoundingClientRect();
		var offset = arguments.callee.offset;
		return {
		     left: rect.left + offset,
		     right: rect.right + offset,
		     top: rect.top + offset,
		     bottom: rect.bottom + offset
		};
	} else {
   		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
	   }
	}
}

这个函数在 getBoundingClientRect()有效时,就使用这个原生方法,而在这个方法无效时则使用默认的计算公式。在某些情况下,这个函数返回的值可能会有所不同,例如使用表格布局或使用滚 动元素的情况下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值