Dom-extend

a. 选择符API

Selectors API Level 1 的核心是两个方法: querySelector()和 querySelectorAll()。目前已完全支持 Selectors API Level 1
的浏览器有 IE 8+、 Firefox 3.5+、 Safari 3.1+、 Chrome 和 Opera 10+。

o> querySelector(“css选择符”) —> 返回匹配选择符的第一个元素,若没有匹配返回null。
1
2
3
4
var body = document.querySelector("body");
var myDiv = document.querySelector("#myDiv");
var selected = document.querySelector(".selected");
var img = document.querySelector("img.button");
o> querySelectorAll(“css选择符”) —-> 返回匹配选择符的所有元素, 返回的是一个NodeList的实例。
o> Selectors API Level 2 规范为 Element 类型新增了一个方法 matchesSelector(“CSS 选择符”)。调用元素与该选择符匹配返回true, 否则返回false;
1
2
3
4
5
6
7
8
9
10
11
12
13
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.msMatchesSelector(selector);
}else if(element.webkitMatchesSelector){
return element.webkitMatchesSelector(selector);
}else{
throw new Error("Not Supported!");
}
}

b.元素遍历

o> 对于元素间的空格, IE9 及之前版本不会返回文本节点,而其他所有浏览器都会返回文本节点。这样,就导致了在使用 childNodes 和 firstChild 等属性时的行为不一致。为了弥补这一差异,而同时又保持 DOM 规范不变, Element Traversal 规范(www.w3.org/TR/ElementTraversal/)新定义了一组属性。支持的浏览器为 DOM 元素添加了这些属性,利用这些元素不必担心空白文本节点.

Element Traversal API 为 DOM 元素添加了以下 5 个属性。
 childElementCount:返回子元素(不包括文本节点和注释)的个数。
 firstElementChild:指向第一个子元素; firstChild 的元素版。
 lastElementChild:指向最后一个子元素; lastChild 的元素版。
 previousElementSibling:指向前一个同辈元素; previousSibling 的元素版。
 nextElementSibling:指向后一个同辈元素; nextSibling 的元素版。

支持 Element Traversal 规范的浏览器有 IE 9+、 Firefox 3.5+、 Safari 4+、 Chrome 和 Opera 10+。

1
2
3
4
5
6
7
var i,len,
child = element.firstElementChild;

while(child != element.lastElementChild){
processChild(child); //已知其是元素
child = child.nextElementSibling;
}

c. HTML5

o> getEelementsByClassName() 返回NodeList的实例。

· IE 9+、 Firefox 3+、 Safari 3.1+、 Chrome 和 Opera 9.5+。

o> classList 属性 (DOMTokenList 的实例): 添加、删除和替换类名。

支持 classList 属性的浏览器有 Firefox 3.6+和 Chrome。
DOMTokenList 有一个表示自己包含多少元素的 length 属性,而要取得每个元素可以使用 item()方法,也可以使用方括号语法。

 add(value):将给定的字符串值添加到列表中。如果值已经存在,就不添加了。
 contains(value):表示列表中是否存在给定的值,如果存在则返回 true,否则返回 false。
 remove(value):从列表中删除给定的字符串。
 toggle(value):如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它。

1
2
3
4
5
6
<div class="bd user disabled"></div>

var div = document.getElementsByTagName('div')[0];
div.classList.remove("user");
div.classList.add("current");
div.classList.toggle("disabled");
o> 焦点管理
i> document.activeElement : 始终会引用DOM中当前获得了焦点的元素。
默认情况下,文档刚刚加载完成时, document.activeElement 中保存的是 document.body 元素的引用。文档加载期间, document.activeElement 的值为 null。
i> docuemnt.hasFocus() : 用于确定文档是否获得了焦点。

实现了这两个属性的浏览器的包括 IE 4+、 Firefox 3+、 Safari 4+、 Chrome 和 Opera 8+。

o> HTMLDocument的变化
i> readyState 属性。
Document 的 readyState 属性有两个可能的值:
   -- loading : 正在加载文档
   -- complete : 文档已经加载完成
支持 readyState 属性的浏览器有 IE4+、 Firefox 3.6+、 Safari、 Chrome 和 Opera 9+。
i> 兼容模式: compatMode属性
自从 IE6 开始区分渲染页面的模式是标准的还是混杂的
  -- CSS1Compat : 在标准模式下
  -- BackCompat : 在混杂模式下

支持compatMode属性的浏览器有 IE6+ Firefox、 Safari 3.1+、 Opera 和 Chrome

i> document.head 属性
实现 document.head 属性的浏览器包括 Chrome 和 Safari 5

1
var head = document.head || document.getElementsByTagName("head")[0];
i> document.charset 字符集属性(可读取设置)
默认情况下,这个属性的值为"UTF-16",但可以通过<meta>元素、响应头部或直接设置 charset 属性修改这个值。
支持 document.charset 属性的浏览器有 IE、 Firefox、 Safari、 Opera 和 Chrome。

defaultCharset属性表示根据默认浏览器及操作系统的设置,当前文档默认的字符集应该是什么。如果文档没有使用默认的字符集,那 charset 和 defaultCharset 属性的值可能会不一样。
支持document.defaultCharset 属性的浏览器有 IE、 Safari 和 Chrome。
i> 自定义数据属性

HTML5 规定可以为元素添加非标准的属性,但要添加前缀 data-,目的是为元素提供与渲染无关的信息,或者提供语义信息。这些属性可以任意添加、随便命名,只要以 data-开头即可。

可以通过元素的 dataset 属性来访问自定义属性的值

1
2
var appid = div.dataset.appid;
div.dataset.appid = 1234;

支持自定义数据属性的浏览器有 Firefox 6+和 Chrome。

i> 插入标记

ii> innerHTML 属性
 为 innerHTML 设置的包含 HTML 的字符串值与解析后 innerHTML 的值大不相同。

1
2
eg : div.innerHTML = "Hello & welcome, <b>\"reader\"!</b>";
==> <div id="content">Hello &amp; welcome, <b>&quot;reader&quot;!</b></div>

 在读取模式下,innerHTML 属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应的HTML标记。
 在写模式下,innerHTML 会根据指定的值创建新的 DOM树, 然后用这个 DOM树 完全替换调用元素原先的所有子节点。
 通过 innerHTML 插入 <script> 元素并不会执行其中的脚本。IE8及更早版本是唯一能在这种情况下执行脚本的浏览器
 条件:一是必须为<script>元素指定 defer 属性,二是<script>元素必须位于(微软所谓的) “有作用域的元素”(scoped element)之后。

1
div.innerHTML = "<script defer>alert('hi');<\/script>"; //无效

此时, innerHTML字符串一开始(而且整个)就是一个“无作用域的元素”,所以这个字符串会变成空字符串。如果想插入这段脚本,必须在前面添加一个“有作用域的元素”,可以是一个文本节点,
也可以是一个没有结束标签的元素如<input>。例如,下面这几行代码都可以正常执行:

1
2
3
4
div.innerHTML = "_<script defer>alert('hi');<\/script>";
div.innerHTML = "<div>&nbsp;</div><script defer>alert('hi');<\/script>";
//首选:由于隐藏的<input>域不影响页面布局,其它两个都要删除前面多余的文本
div.innerHTML = "<input type=\"hidden\"><script defer>alert('hi');<\/script>";

 插入<style>元素:<style>也是一个“没有作用域的元素”,因此必须像下面这样给它前置一个“有作用域的元素”。
 不同浏览器返回的文本格式会不相同。(大小写和空格)
 并不是所有元素都支持 innerHTML 属性。不支持 innerHTML 的元素有: <col>、 <colgroup>、<frameset>、 <head>、 <html>、 <style>、 <table>、 <tbody>、 <thead>、 <tfoot>和<tr>。此外,在 IE8 及更早版本中, <title>元素也没有 innerHTML 属性。

ii> outerHTML 属性
在读取模式下,outerHTML 返回调用它的元素及所有子节点的HTML标签。
在写模式下, outerHTML会根据指定的HTML字符串创新的DOM子树,然后用这个DOM子树完全替换调用元素。

ii> insertAdjacentHTML( 插入位置, 要插入的HTML文本)方法
第一个参数必须是下列值之一(这些值必须都是小写形式):

  • “beforebegin” : 在当前元素之前插入一个紧邻的同辈元素
  • “afterbegin” : 在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;
  • “beforeend” : 在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素
  • “afterend” : 在当前元素之后插入一个紧邻的同辈元素。

ii> 内存和性能问题:
在删除带有事件处理程序或引用了其他 JavaScript 对象子树时,就有可能导致内存占用问题。假设某个元素有一个事件处理程序(或者引用了一个 JavaScript对象作为属性),在使用前述某个属性将该元素从文档树中删除后,元素与事件处理程序(或JavaScript对象)之间的绑定关系在内存中并没有一并删除。如果这种情况频繁出现,页面占用的内存数量就会明显增加。因此,在使用 innerHTML、outerHTML 属性和 insertAdjacentHTML()方法时,最好先手工删除要被替换的元素的所有事件处理程序和 JavaScript 对象属性。

在使用innerHTML属性时,在设置 innerHTML 或 outerHTML 时,就会创建一个 HTML解析器。这个解析器是在浏览器级别的代码(通常是 C++编写的)基础上运行的,因此比执行 JavaScript快得多。不可避免地,创建和销毁 HTML 解析器也会带来性能损失,所以最好能够将设置 innerHTML或 outerHTML 的次数控制在合理的范围内。

1
2
3
4
5
6
7
8
9
10
11
这种做法效率低下,占用内存多
for(var i = 0, len = values.length; i < len; i++){
ul.innerHTML += "<li>" + values[i] + "</li>";
}

最好的做法是:单独创建一个字符串,然后一次性地将结果字符串赋值给 innerHTML
var innerHtml = "";
for(var i = 0, len = values.length; i < len; i++){
innerHtml += "<li>" + values[i] + "</li>";
}
ul.innerHTML = innerHtml;

ii> 插入文本 innerText
通过 innertText 属性可以操作元素中包含的所有文本内容,包括子文档树中的文本。
在通过innerText 读取值时,它会按照由浅入深的顺序,将子文档树中的所有文本拼接起来。由于不同浏览器处理空白符的方式不同,因此输出的文本可能会也可能不会包含原始 HTML 代码中的缩进。
在通过innerText 写入值时,结果会删除元素的所有子节点,插入包含相应文本值的文本节点。也对文本中存在的 HTML语法字符(小于号、大于号、引号及和号)进行了编码。

支持 innerText 属性的浏览器包括 IE4+、 Safari 3+、 Opera 8+和 Chrome。 Firefox 虽然不支持innerText,但支持作用类似的 textContent 属性。

兼容写法:

1
2
3
4
5
6
7
8
9
10
11
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;
}
}