《JavaScript高级程序设计》笔记:DOM2和DOM3(十二)
dom1级主要定义的是html和xml文档的底层结构。dom2级和dom3级在这个结构基础上引入了更多的交互能力,也支持更高级的xml特性。为此dom2级和dom3级分为了很多的模块(模块直接具有某种关联),分别描述了dom的某个非常具体的子集。这些模块如下:
- dom2级核心:在1级核心基础上构建,为节点添加了更多属性和方法;
- dom2级视图:为文档定义了基于样式信息的不同视图;
- dom2级事件:说明了如何使用事件与dom文档交互;
- dom2级样式:定义了如何以编程方式来访问和改变css样式信息;
- dom2级遍历和范围:引入了遍历dom文档和选择其特定部分的新接口;
- dom2级html:在1级html基础上构建,添加了更多的属性、方法和新接口。
dom变化
dom2级和dom3级的目的在于扩展dom api,以满足操作xml的所有需求,同时提供更好的错误处理级特性检测能力。
通过下列代码来确定浏览器是否支持这些dom模块:
var supportsdom2core = document.implementation.hasfeature("core","2.0"); var supportsdom3core = document.implementation.hasfeature("core","3.0"); var supportsdom2html = document.implementation.hasfeature("html","2.0"); var supportsdom2views = document.implementation.hasfeature("views","2.0"); var supportsdom2xml = document.implementation.hasfeature("xml","2.0");
针对xml命名空间的变化
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml"> <xhtml:head> <xhtml:title>example xhtml page</xhtml:title> </xhtml:head> <xhtml:body xhtml:class="home"> hello world! </xhtml:body> </xhtml:html>
样式
访问元素的样式
对于使用短横线(例如:background-image)的css属性名,必须将其转换为驼峰大小写形式,才能通过javascript来访问。如下:
var mydiv = document.getelementbyid('mydiv'); mydiv.style.backgroundcolor = 'red'; mydiv.style.width = '200px'; mydiv.style.height = '200px'; mydiv.style.border = '1px solid #ccc';
其中一个不能直接转化的css属性为float。由于float为javascript的保留字,因此不能作为属性名。“dom2级样式”规范规定对象上相应的属性名应该是cssfloat。除了ie浏览器,其它浏览器都支持这个属性。而ie支持的是stylefloat。
dom样式属性和方法
“dom2级样式”规范为style对象定义了一些属性和方法,常用:
- csstext:通过它可以访问到style特性中的css代码。
- length:应用给元素的css属性的数量。
- getpropertyvalue(propertyname):返回给定属性的字符串值。
- item(index):返回给定位置的css属性的名称。
- removeproperty(propertyname):从样式中删除给定的属性。
- setproperty(propertyname,value,priority):将给定的属性设置为相应的值,并加上优先权标志(“important”或者一个空字符串)。
var mydiv = document.getelementbyid('page1'); mydiv.style.csstext = "display:block;width:300px;background:red;color:#fff;" console.log(mydiv.style.csstext); //display: block; width: 300px; background: red; color: rgb(255, 255, 255);
设置csstext是为元素应用多项变化最快捷的方式,因为可以一次性的应用所有变化。
var mydiv = document.getelementbyid('page1'); var i,len,prop,value; for(i =0, len = mydiv.style.length; i < len; i++){ prop = mydiv.style[i]; //或者 mydiv.style.item(i) value = mydiv.style.getpropertyvalue(prop); console.log(prop + ":" + value); } mydiv.style.removeproperty('font-size');
计算的样式
虽然style对象能够提供支持style特性的任何元素的样式信息,但它不包含从其它样式表层叠而来并影响当前元素的样式信息。“dom2级样式”增强了document.defaultview,提供了getcomputedstyle()方法。这个方法接收两个参数:要取得计算样式的元素和一个伪元素字符串(例如":after")。如果不需要伪元素,那么第二个参数可以为null。getcomputedstyle()方法返回一个cssstyledeclaration对象(与style属性的类型相同),其中包含当前元素的所有计算的样式。
var mydiv = document.getelementbyid('page1'); var computedstyle = document.defaultview.getcomputedstyle(mydiv,null); console.log(computedstyle.width); console.log(computedstyle.backgroundcolor);
ie不支持getcomputedstyle()方法,但是在ie中,每个具有style属性的元素还有一个currentstyle属性。这个属性是cssstyledeclaration的实例,包含当前元素全部计算后的样式。
var mydiv = document.getelementbyid('page1'); var computedstyle = mydiv.currentstyle; console.log(computedstyle.width); console.log(computedstyle.backgroundcolor);
操作样式表
cssstylesheet类型表示的是样式表。应用于文档的所有样式表是通过document.stylesheets集合来表示的。
var sheet = null; for(var i =0, len = document.stylesheets.length; i < len; i++){ sheet = document.stylesheets[i]; console.log(sheet.href); }
上面例子是获取每一个样式表的href属性。
不同浏览器的document.stylesheets返回的样式表不同,dom规定了一个包含cssstylesheet对象的属性,名叫sheet,除了ie浏览器,其它浏览器都支持;ie支持的是stylesheet属性。在不同浏览器取得样式表对象,代码如下:
function getstylesheet(element){ return element.sheet || element.stylesheet; } //取得第一个link元素引入的样式表 var link = document.getelementsbytagname('link')[0]; var sheet = getstylesheet(link); console.log(sheet);
得到的结果如下图:
这里的getstylesheet()返回的样式表对象和document.stylesheets集合中的样式表对象相同。
元素大小
1.偏移量
- offsetheight:元素在垂直方向上占用的空间大小,以像素计算。包括元素的高度、(可见的)水平滚动条的高度、上边框高度和下边框高度。
- offsetwidth:元素在水平方向上占用的空间大小,以像素计算。包括元素的宽度、(可见的)垂直滚动条的宽度、左边框宽度和右边框宽度。
- offsetleft:元素的左外边框至包含元素的左内边框之间的像素距离。
- offsettop:元素的上外边框至包含元素的上内边框之间的像素距离。
其中offsetleft和offsettop属性跟包含元素有关,包含元素的引用保存在offsetparent属性中。offsetparent属性不一定与parentnode的值相等。
例如,<td>元素的offsetparent是作为其祖先元素的<table>元素,因为<table>是在dom层次中距<td>最近的一个具有大小的元素。如下图:
计算某个元素在页面上的偏移量,如下代码分别取得元素的左和上偏移量:
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; } var mydiv = document.getelementbyid('page1'); console.log(getelementleft(mydiv)); console.log(getelementtop(mydiv));
2.客户区大小
元素的客户区大小,指的是元素内容及其内边距所占据的空间大小。有关客户区大小的属性有两个:clientwidth和clientheight。
- clientwidth:元素内容区宽度加上左右内边距宽度(因此滚动条占据的空间不计算在内)。
- clientheight:元素内容区高度加上上下内边距高度(因此滚动条占据的空间不计算在内)。
如图所示描述:
例如:要确认浏览器视口大小,可以使用document.documentelement或document.body(ie7之前的版本中)的clientwidth和clientheight。
function getviewport(){ if(document.compatmode == 'backcompat'){ //ie7浏览器之前 return { width:document.body.clientwidth, height:document.body.clientheight } }else{ //标准浏览器 document.compatmode 为css1compat return { width:document.documentelement.clientwidth, height:document.documentelement.clientheight } } } var result = getviewport(); console.log(result.width); console.log(result.height);
3.滚动大小
滚动大小,指的是包含滚动内容的元素的大小。有的元素(例如<html>元素),即使没有执行任何代码也能自动添加滚动条;但另外一些元素,需要通过设置css的overflow属性进行设置才能滚动。以下有四个跟滚动相关的属性:
- scrollheight:在没有滚动条的情况下,元素内容的总高度。
- scrollwidth:在没有滚动条的情况下,元素内容的总宽度。
- scrollleft:被隐藏在内容区域左侧的像素数。通过设置这个属性可以改变元素的滚动位置。
- scrolltop:被隐藏在内容区域上方的像素数。通过设置这个属性可以改变元素的滚动位置。
其中scrollheight和scrollwidth主要用于确定元素内容的实际大小。比如带有垂直滚动条的页面总高度为document.documentelement.scrollheight。
对于不包含滚动条的页面而言,scrollwidth和scrollheight与clientwidth和clientheight之间的关系并不十分清晰。在这种情况下,基于document.documentelement查看这些属性会在不同浏览器之间发现一些不一致的问题,如下描述:
- firefox中这两组属性始终是相等的,但大小代表的是文档内容区域的实际尺寸,而非视口的尺寸。
- opera、safari3.1及更高版本、chrome中的这两组属性是有差别的,scrollwidth和scrollheight等于视口大小,而clientwidth和clientheight等于文档内容区域的大小。
- ie(标准模式)中的这两组属性不相等,其中scrollwidth和scrollheight等于文档内容区域的大小,而clientwidth和clientheight等于视口的大小。
在确定文档的总高度时(包括基于视口的最小高度时),必须取得scrollwidth/scrollheight和clientwidth/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。
检测元素是否位于顶部,不是就将其滚到顶部:
function scrolltotop(element){ if(element.scrolltop != 0){ element.scrolltop = 0; } }
4.确定元素的大小
每个元素有getboundingclientrect()方法,这个方法返回一个矩形对象。包含4个属性:left、top、right和bottom。这些属性给出了元素在页面中相对于视口的位置。但是浏览器的实现稍有不同,ie8及更早版本认为文档的左上角坐标为(2,2),而其它的浏览器包括ie9把(0,0)作为起点坐标。下面实现一个跨浏览器兼容的getboundingclientrect版本:
function getboundingclientrect(element){ var scrolltop = document.documentelement.scrolltop || document.body.scrolltop; var scrollleft = document.documentelement.scrollleft || document.body.scrollleft; if(element.getboundingclientrect){ if(typeof arguments.callee.offset != 'number'){ var temp = document.createelement('div'); temp.style.csstext = "position:absolute;top:0;left:0;"; document.body.appendchild(temp); arguments.callee.offset = - temp.getboundingclientrect().top - screentop; 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 - screentop, bottom:actualtop + element.offsetheight - scrolltop }; } }
范围
为了让开发人员更方便的控制页面,“dom2级遍历和范围”模块定义了“范围”(range)接口。通过范围可以选择文档中的一个区域,而不必考虑节点的界限(选择在后台完成,对用户是不可见的)。在常规的dom操作不能更有效地修改文档时,使用范围往往可以达到目的。但ie以专有的方式实现了自己的范围特性。
dom中的范围
dom2级在document类型中定义了createrange()方法。在兼容dom的浏览器中,这个方法属于document对象。使用hasfeature或者直接检测该方法。如下代码:
var supportsrange = document.implementation.hasfeature("range","2.0"); var alsosupportsrange = (typeof document.createrange == 'function');
如果浏览器支持范围,就可以使用createrange()来创建dom范围,如下所示:
var range = document.createrange();
每个范围由一个range类型的实例表示,这个实例拥有很多的属性和方法。下列属性提供了当前范围在文档中的位置信息。
- startcontainer:包含范围起点的节点(即选区中第一个节点的父节点)。
- startoffset:范围在startcontainer中的起点的偏移量。如果startcontainer是文本节点、注释节点、cdata节点,那么startoffset就是范围起点之前跳过的字符数量。否则,startoffset就是范围中第一个子节点的索引。
- endcontainer:包含范围终点的节点(即选区中最后一个节点的父节点)。
- endoffset:范围在endcontainer中终点的偏移量(与startoffset遵循相同的取值规则)。
- commonancestorcontainer:startcontainer和endcontainer共同的祖先节点在文档树中位置最深的那个。
在把范围放到文档中特定的位置时,这些属性都会被赋值。
1.用dom范围实现简单选择
要使用范围来选择文档中的一部分,最简单的方式是使用selectnode()和selectnodecontents()。这两个方法都接受一个参数,即一个dom节点,然后使用该节点的信息来填充范围,其中selectnode()方法选择整个节点,包括其子节点;而selectnodecontents()方法则只选择节点的子节点。如下例子:
<body> <p id="p1"><b>hello</b> world!</p> <script type="text/javascript"> var range1 = document.createrange(); var range2 = document.createrange(); var p1 = document.getelementbyid('p1'); range1.selectnode(p1); range2.selectnodecontents(p1); </script> </body>
2.用dom范围实现复杂选择
要创建复杂的范围就得使用setstart()和setend()方法。这两个方法都接受两个参数:一个参照节点和一个偏移量值。
3.操作dom范围中的内容
- deletecontents():从文档中删除范围所包含的内容。
- extractcontents():从文档中移除范围选区,跟deletecontents()的方法的区别在于会返回范围的文档片段。
- clonecontents():创建范围对象的一个副本。
4.插入dom范围中的内容
- insertnode()
- surroundcontents()
5.折叠dom范围
- collapse()
6.比较dom范围
- compareboundarypoints()
7.复制dom范围
- clonerange()
8.清理dom范围
- detach()
ranage.detach(); range = null;
上一篇: 理解运用JS的闭包、高阶函数、柯里化
下一篇: vuex的使用
推荐阅读
-
《JavaScript高级程序设计(第三版)》读书笔记01 变量、作用域和内存问题
-
《JavaScript高级程序设计》笔记:DOM2和DOM3(十二)
-
JavaScript高级程序设计 阅读笔记(十二) js内置对象Math_javascript技巧
-
JavaScript高级程序设计阅读笔记(十六) javascript检测浏览器和操作系统-detect.js_javascript技巧
-
JavaScript高级程序设计 阅读笔记(十二) js内置对象Math_javascript技巧
-
JavaScript高级程序设计(第3版)学习笔记4 js运算符和操作符_基础知识
-
JavaScript高级程序设计阅读笔记(十六) javascript检测浏览器和操作系统-detect.js_javascript技巧
-
《JavaScript高级程序设计》笔记:DOM2和DOM3(十二)
-
JavaScript高级程序设计(第3版)学习笔记4 js运算符和操作符_基础知识