文章目录
DOM第主要两个扩展是SelectorsAPI(选择符API)和HTML5。
选择符扩展
根据CSS选择符选择与某个模式匹配第DOM元素。
jQuery(www.jquery.com)的核心就是通过CSS选择符查询DOM文档取得元素第引用,从而抛开了getElementById()和getElementsByTagName()。
Selectors API(www.w3.org/TR/selectors-api/)由w3c发起制定,致力于让浏览器原生支持CSS查询。
Selectors API Level 1的核心是两个方法:querySelector()和querySelectorAll()。在兼容第浏览器中,可以通过Document及Element类型第实例调用他们。
目前已完全支持Selectors API Level 1的浏览器有IE8+、Firefox 3.5+、Safari 3.1+、Chrome和Opera 10+。
querySelector()方法
该方法接收一个CSS选择符,返回与该模式匹配第第一个元素,如果没有找到匹配第元素,返回null。
//取得body元素
var body = document.querySelector("body");
//取得ID为“myDiv”的元素
var myDiv = document.querySelector("#myDiv");
//取得类为"selected"的第一个元素
var selected = document.querySelector(".selectd");
//取得类为"button"的第一个图像元素
var img = document.body.querySelector("img.button");
通过Document类型调用querySelector()方法时,会在文档元素的范围内查找匹配第元素。通过Element类型调动querySelector()方法时,只会在该元素后代元素第范围内查找匹配的元素。
CSS选择符可以简单也可以复杂,如果传入了不被支持第选择符,querySelector()会抛出错误。
querySelectorAll()方法
该方法返回一个NodeList实例,包含了所有匹配的元素。具体来说,返回第之实际上是带有所有属性和方法第NodeList,而其底层实现类似于一组元素第快照,而非不断对文档进行搜索第动态查询。这样实现尅避免使用NodeList对象通常会引起第大多数性能问题。
能够调用querySelectorAll()方法第类型包括Document、DocumentFragment和Element。
//取得某个<div>中的所有<em>元素(类似于getElementsByTagName("em)
var ems = document.getElementById("myDiv").querySelectorAll("em");
//取得类为"selected"的所有元素
var selecteds = document.querySelectorAll(".selected");
//取得所有<p>元素中的所有<strong>元素
var strongs = document.querySelectorAll("p strong");
要取得返回的NodeList中的每一个元素,可以使用item()方法,也可以使用方括号语法:
var i, len, strong;
for(i=0, len=strongs.length; i < len; i++) {
strong = strongs[i]; //或者strongs.item(i)
strong.className = "important";
}
matchesSelector()方法
Selectors API Level 2规范为Element类型新增了一个方法matchesSelector(),该方法接收一个参数:CSS选择符,如果调用元素与该选择符匹配,返回true;否则,返回false.
if (document.body.matchesSelector("body.page1")){
//true
}
在取得某个元素引用的情况下,使用这个方法能够方便地检测它是否会被querySelector()或querySelectorAll()方法返回。
由于兼容性问题,现在各个浏览器都只支持加前缀的方法。IE9+浏览器支持msMatchesSelector()方法,firefox支持mozMatchesSelector()方法,safari和chrome支持webkitMatchesSelector()方法。所以兼容写法为:
function matchesSelector(element, selector) {
if (element.matchesSelector) {
return element.matchesSelector(selector);
} else if (element.msMatchesSelector) {
return element.msMatchesSelector(selector);
} else if (element.mozMatchesSelector) {
return element.mozMatchesSelector(selector);
} else if (element.webkitMatchesSelector) {
return element.webkitMatchesSelector(selector);
} else {
throw new Error("Not supported.");
}
}
if (matchesSelector(document.body, "body.page1")) {
//执行操作
}
元素遍历
Element Traversal API为DOM元素添加了以下5个属性。
- childElementCount:返回子元素(不包括文本节点和注释)的个数。
- firstElementChild:指向第一个子元素;firstChild的元素版。
- lastElementChild:指向最后一个子元素;lastChild的元素版。
- previousElementSibling:指向前一个同辈元素;previousSibling的元素版。
- nextElementSibling:指向后一个同辈元素;nextSibling的元素版。
例如要跨浏览器遍历某元素第所有子元素,需要如下编码:
var i,
len,
child = element.firstChld;
while(child != element.lastChild) {
if(child.nodeType == 1) { //检查是不是元素
processChild(child);
}
child = child.nextSibling;
}
使用Element Traversal新增元素:
var i,
len,
child = element.firstElementChild;
while(child != element.lastElementChild) {
processChild(child); //已知其是元素
child = child.nextElementSibling;
}
支持Element Traversal规范的浏览器有IE9+、Firefox 3.5+、Safari 4+、Chrome和Opera 10+.
HTML5
与类相关的扩充
- getElementsByClassName()方法
该方法是HTML5新增方法,可以通过document对象及所有HTML元素调用,该方法接收一个参数:一个包含一或多个类名第字符串,返回带有制定类第所有元素第NodeList。
//取得所有类中包含“username”和“current”的元素,类名的先后顺序无所谓
var allCurrentUsernames = document.getElementsByClassName("username current");
//取得ID为“myDiv”的元素中带有类名“selected”的所有元素
var selected = document.getElementById("myDiv").getElementsByClassName("selected");
支持getElementsByClassName()方法的浏览器有IE9+、Firefox 3+、Safari 3.1+、Chrome和Opera 9.5+。
2. classList属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div class="db user disabled">……</div>
<script>
var div = document.getElementBysTagName("div")[0];
//删除“user”类
//首先,取得类名字符串并拆分成数组
var classNames = div.className.split(/\s+/);
//找到要删除第类名
var pos = -1,
i,
len;
for(i = 0, len = classNames.length; i < len; i++) {
if (classNames[i] == "user") {
pos = i;
break;
}
}
//删除类名
classNames.splice(i ,1);
//把剩下第类名拼成字符串并重新设置
div.className = classNames.join(" ");
</script>
</body>
</html>
classList属性是新集合类型DOMTokenList的实例。该属性定义了如下方法:
- add(value):将给定的字符串值添加到列表中。如果值已存在,就不添加了。
- contains(value):表示列表中是否存在给定的值,如果存在则返回true,否则返回false。
- remove(value):从列表中删除给定字符串。
- toggle(value):如果列表中已经存在给定的值,删除它;如果不存在添加它。
以上代码可以用下面一行代码代替
div.classList.remove("user");
支持classList属性的浏览器有Firefox 3.6+和Chrome
焦点管理
HTML5添加了辅助管理DOM焦点的功能。首先是document.activeElement属性,这个属性始终会引用DOM中当前获得了焦点的元素。默认情况下,文档刚刚加载完成时,document.activeElement中保存的是document.body元素的引用。文档加载期间,document.activeElement的值为null。
另外就是新增了document.hasFocus()方法,这个方法用于确定文档是否获得了焦点。
var button = document.getElementById("myButton");
button.focus();
alert(document.hasFocus()); //true
实现了这两个属性的浏览器包括IE4+、Firefox 3+、Safari4+、Chrome和Opera8+。
HTMLDocument的变化
- readyState属性
Document的readyState属性有两个可能的值:
- loading,正在加载文档;
- complete,已经加载完成文档。
- 兼容模式
IE给document添加了一个名为compatMode的属性,这个属性告诉开发人员浏览器采用了哪种渲染方式。
在标准模式下,document.compatMode的值等于“CSS!Compat”,而在混杂模式下,document.compatMode的值等于“BackCompat”。 - head属性
HTML5新增了document.head属性,引用文档的元素。
字符集属性
charset属性表示文档中实际使用第字符集,也可以用来指定新字符集。默认情况下,这个属性的值为“UTF-16”,可以通过元素、响应头部或直接设置charset属性修改这个值。
defaultCharset表示根据浏览器及操作系统的设置,当前文档默认的字符集应该是什么。
if(document.charset != document.defaultCharset {
alert("Custom character set being used.");
}
通过这两个属性可以得到文档使用第字符编码第具体信息,也能对字符编码进行准确地控制。
支持document.charset属性的浏览器有:IE、Firefox、Safari、Opera和Chrome。
支持document.defaultCharset属性的浏览器有IE、Safari和Chrome。
自定义数据属性
HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,目的是为元素提供与渲染无关的信息,或者提供语义信息。
<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
添加了自定义属性后,可以通过元素的dataset属性来访问自定义属性的值。dataset属性第值是DOMStringMap的一个实例,是一个名值对第映射。每个data-name形式的属性东欧会有一个对应的属性,只不过属性名没有data-前缀(如:自定义属性是data-myname,那映射中对应的属性就是myname)。
//本例中使用第方法仅用于演示
var div = document.getElementById("myDiv");
//取得自定义属性的值
var appId = div.dataset.appId;
var myName = div.dataset.myname;
//设置值
div.dataset.appId = 23456;
div.dataset.myname = "Michael";
//有没有"myname"值呢?
if(div.dataset.myname){
alert("Hello, " + div.dataset.myname);
}
需要给元素添加一些不可见第数据以便进行其他处理时就要用到自定义数据属性。
插入标记
DOM为操作节点提供了细致入微的控制手段,但在需要给文档插入大量新HTML标记第情况下,通过DOM操作非常麻烦,不仅要创建一些列DOM节点,而且还要小心地按照正确的顺序把它们连接起来。
- innerHTML属性
在读模式下,innerHTML属性返回与调用元素第所有子节点(包括元素、注释和文本节点)对应第HTML标记。
在写模式下,innerHTML会根据指定第值创建新第DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。
如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="content">
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</body>
</html>
以上代码
不同浏览器返回第文本格式会有所有不同。IE和Opera会将所有标签转换为大写,Safari、Chrome和Firefox会原样返回。
为innerHTML设置HTML字符串后,浏览器会将这个字符串解析为相应的DOM树,设置了innerHTML之后,再从中读取HTML字符串,会得到与设置时不一样第结果。原因在于返回的字符串是根据原始HTML字符串创建的DOM树经过序列化之后第结果。
innerHTML使用限制:通过innerHTML插入
// div.innerHTML = "<script defer>alert('hi');<\/script>"; //无效
div.innerHTML = "_<script defer>alert('hi');<\/script>"
div.innertHTML = "div.&*nbsp;</div><script defer>alert('hi');<\/.script>";
div.innerHTML = "<input type = \"hidden\"><script defer>alert("'hi'>;<\/script>;
innerHTML字符串一开始就是一个“无作用域的元素”,所以这个字符串会变成空字符串。如果想插入这段脚本,必须在前面添加一个“有作用域”的元素,可以是一个文本节点,也可以是一个没有结束标签第元素如。
第一行代码会在
大多数浏览器都支持以直观的方式通过innerHTML插入
div.innerHTML = "<style type=\"text/css\">body {background-color: red;}</style>";
在IE8及更早版本在红,
div.innerHTML = "_<style type=\"text/css\">body {background-color: red;}</style>";
div.removeChild(div.firstChild);
并不是所有元素都支持innerHTML属性,不支持innerHTML的元素有:、、、、、
Firefox对在内容类型为application/xhtml+xml的XHTML文档中设置innerHTML有严格的限制。在XHTML文档中使用innerHTML时,XHTML代码必须完全符合要求。如果代码格式不正确,设置innerHTML将会静默地失败。
使用innerHTML从外部插入HTML,都应该首先以可靠第方式处理HTML。IE8为此提供了window.toStaticHTML()方法,该方法接收一个参数:HTML字符串,返回一个经过无害处理后的版本——从源HTML中删除所有脚本节点和事件处理程序属性。目前只有IE8原生支持这个方法。
-
outerHTML属性
在读模式下,outerHTML()返回调用它的元素及所有子节点的HTML标签。
在写模式下,outerHTML()会根据指定的HTML字符串创建新的DOM子树,然后用这个DOM子树完全替换调用元素。
支持outerHTML属性的浏览器有IE4+、Safari 4+、Chrome和Opera 8+。Firefox 7及之前第版本都不支持outerHTML属性。 -
insertAdjacentHTML()方法
该方法接收两个参数:插入位置和要插入的HTML文本。
第一个参数必须是下列值之一:
- beforebegin:在当前元素之前插入一个紧邻的同辈元素;
- afterbegin:在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;
- beforeend:在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素;
- afterend:在当前元素之后插入一个紧邻的同辈元素。
以上值必须是小写形式
//作为前一个同辈元素插入
element.insertAdjacentHTML("beforebegin","<p>Hello world!</p>");
//作为第一个子元素插入
element.insertAdjacentHTML("afterbegin", "<p>Hello world!</p>");
//作为最后一个子元素插入
element.insertAdjacentHTML("beforeend", "<p>Hello world!</p>");
//作为最后一个同辈元素插入
element.insertAdjacentHTML("afterend", "<p>Hello world!</p>")
- 内存与性能问题
在删除带有时间处理程序或引用了其他javascript对象子树时,有可能导致内存占用问题,因为将元素从文档树种删除后,元素与事件处理程序(或JavaScript对象)之间的绑定关系在内存中并没有一起删除,这种情况及时出现,页面占用的内存数量会会明显增加。因此,在使用innerHTML、outerHTML属性和insertAdjacentHTML()方法时,最好先手工删除要替换第元素的所有事件处理程序。
scrollIntoview()方法
scrollIntoview()可以在所有HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中。
如果给这个方法传入true作为参数,或者不传入任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐。如果传入false作为参数,调用元素会尽可能全部出现在视口中,(可能的话,调用元素第底部会与视口顶部平齐。)
//让元素可见
document.forms[0].scrollIntoView();
支持scrollIntoView()方法的浏览器有IE、Firefox、Safari和Opera。
专有扩展
文档模式
IE8引入了“文档模式”的概念,文档模式决定了你可以使用哪个级别第CSS,可以在JavaScript中使用哪些API,以及如何对待文档类型(doctype)。
要强制浏览器以某种模式渲染页面,可以使用HTTP头部信息X-UA-Compatible,或通过等价的标签来设置:
<meta http-equiv="X-UA-Compatible" content="IE=IEVersion">
通过document.documentMode属性尅知道给定页面使用的是什么文档模式。
children顺序属性
这个属性是HTMLCollection的实例,只包含元素中同样还是元素的子节点。
contains()方法
contains()方法判断某个节点是不是另一个节点的后代。
调用contains()方法第应该是祖先节点,也就是搜索开始第节点,接收一个参数,即要检测的后代节点。如果被检测第节点是后代节点,该方法返回true,否则,返回false。
支持contains()方法的浏览器有IE、Firefox9+、Safari、Opera和Chrome。
使用DOM Level3 compareDocumentPosition()也能够确定节点间的关系。支持这个方法的浏览器有IE9+、Firefox、Safari、Opera 9.5+和Chrome。该方法返回一个表示该关系的位掩码(bitmask)。
掩码 | 节点关系 |
---|---|
1 | 无关(给定的节点不在当前文档中) |
2 | 局前 |
4 | 局后(给定的节点在DOM树中位于参考节点之后) |
8 | 包含(给定的节点是参考节点的祖先) |
16 | 被包含(给定的节点是参考节点的后代) |
插入文本
innerText属性和outerText属性未被纳入HTML5规范。
- innerText属性
通过innerText属性可以操作元素中包含的所有文本内容,包括子文档树中的文本。
通过innerText读取时,会按照由浅入深的顺序将子文档树中第所有文本拼接起来。
通过innerText写入时,结果会删除元素第所有子节点,插入包含相应文本值的文本节点。
设置innerText属性时对文本中存在第HTML语法字符(小于号、大于号、引号及和号)进行了编码。
支持innerText属性的浏览器包括IE4+、Safari 3+、Opera 8+和Chrome。Firefox支持作用类似第textContent属性,该属性时DOM Level 3规定第一个属性,其他支持textContent属性第浏览器还有IE9+、Safari 3+、Opera 10+和Chrome。
兼容的通用方法为:
function getInnerText(element) {
return (typeof element.textContent == "String") ? element.textContent : element.innerText;
}
function setInnerText(element, text) {
if (typeof element.textContent == "string") {
element.textContent = text;
} else {
element.innerText = text;
}
}
- outerText属性
outerText读取文本时,结果与innerText一样。
outerText写入文本时,不只是替换调用它第元素的子节点,而是会替换整个元素(包括子节点)。
eg:
div.outerText = “Hello world!”;
执行以上代码相当于:
var text = document.createTextNode(“Hello world!”);
div.parentNode.replaceChild(text,div);
支持outerText属性第浏览器有IE4+、Safari 3+、Opera 8+和Chrome。
这个属性会导致调用它的元素不存在,因此不建议使用。
滚动
以下方法都是对HTMLElement类型第扩展,因此在所有元素中都可以调用。
- scrollIntoViewIfNeeded(alignCenter):只在当前元素在视口中不可见的情况下,才滚动浏览器窗口或容器元素,最终让她可见。如果当前元素在视口中可见,这个方法什么也不做。如果将可选的alignCenter参数设置为true,则表示尽量将元素显示在视口中部(垂直方向)。Safari和Chrome实现了这个方法。
- scrollByLines(lineCount):将元素的内容滚动指定的行高,lineCount值可以是正值,也可以是负值。Safari和Chrome实现了这个方法。
- scrollByPages(pageCount):将元素的内容滚动指定第页面高度,具体高度由元素的高度决定。Safari和Chrome实现了这个方法。
scrollIntoViewIfNeeded()和scrollIntoView(()的作用对象是元素的容器,而scrollByLines()和scrollByPages()影响第则是元素自身。
虽然DOM为与XML及HTML文档交互制定了一系列核心API,但仍然有几个规范对标准的DOM进行了扩展。这些扩展中有很多原来是浏览器专有的,但后来成为了事实标准,于是其他浏览器也都提供了相同的实现。
- Selectors API,定义了两个方法,让开发人员能够基于CSS选择符从DOM中取得元素,这两个方法是querySelector()和querySelectorAll()。
- Element Traversal,为DOM元素定义了额外的属性,让开发人员能够更方便地从一个元素跳到另一个元素。之所以会出现这个扩展,是因为浏览器处理DOM元素间空白符第方式不一样。
- HTML 5,为标准的DOM定义了很多扩展功能。其中包括在innerHTML属性这样第事实标准基础上提供的标准定义,以及为管理焦点、设置字符集、滚动页面而规定的扩展API。