注: IE のすべての DOM オブジェクトは COM オブジェクトの形式で実装されます。これは、IE の DOM オブジェクトの動作またはアクティビティ特性がネイティブ JavaScript オブジェクトと一致しないことを意味します。
DOM レベル 2 コア: レベル 1 コアに基づいて構築され、ノードにメソッドとプロパティを追加
DOM レベル 2 ビュー:ドキュメントのスタイル情報に基づいてさまざまなビューを定義します
DOM レベル 2 イベント: DOM ドキュメント操作でイベントを使用する方法について説明します
DOM レベル2 スタイル: CSS スタイル情報にプログラム的にアクセスして変更する方法を定義します。
DOM2 レベル 2 の走査と範囲: DOM ドキュメントを走査し、その特定の部分を選択するための新しいインターフェイスを導入します。
DOM レベル 2 HTML (DOM レベル 2 HTML): レベル 1 HTML に基づいて構築され、属性、メソッド、新機能が追加されています。
// 判断是否支持模块var DOM2Core = document.implementation.hasFeature('Core',2.0)
DOM1 レベルは Node インターフェイスを定義します。このインターフェイスは、DOM 内のすべてのノード タイプによって実装されます。
JavaScript のすべてのノード タイプ は Node タイプから を継承するため、すべてのノード タイプは同じ基本プロパティとメソッドを共有します。
互換性: IE を除くすべてのブラウザーがこのタイプにアクセスできます。
各ノードには、nodeType 属性があり、ノードのタイプを示します。
ノード タイプは、ノード タイプで定義される 12 個の数値定数によって表されます。以下に、一般的に使用されるものをいくつか示します。
Node.ELEMENT_NODE: 1
Node.TEXT_NODE: 3
Node.COMMENT_NODE: 8
nodeNameとnodeValueを通じてノード情報を知ることができます。これら 2 つのプロパティはノードのタイプによって異なります。
これら 2 つのノードを使用する前に、まずノードのタイプを確認することをお勧めします。
ノードが要素の場合、nodeName は常に要素のタグ名であり、nodeValue は常に 0 です。
各ノードには、NodeList オブジェクトを保持する childNodes 属性があります。 NodeList オブジェクトは、位置によってアクセスできる順序付けされたノードのセットを保持する配列のようなオブジェクトです。
hasChildNodes(): ノードに 1 つ以上の子ノードが含まれる場合、このメソッドは true を返します。
ownerDocument: この属性は、ドキュメント全体を表すドキュメント ノードを指します。
// 将NodeList对象转换为数组var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0);
互換性: IE8 以前では NodeList が COM オブジェクトとして実装されているため、上記のコードはエラーを引き起こします。
注: NdoeList オブジェクトの特別な点は、実際には DOM 構造に基づいてクエリを動的に実行した結果であるため、DOM 内の変更を NodeList オブジェクトに直接反映できることです。それは生きた物体であり、私たちが最初に訪れた瞬間に撮影されたスナップショットではありません。
appendChild(): childNodes リストの末尾にノードを追加するために使用されます。新しく追加されたノードを返します。
insertBefore(): 挿入されるノードと参照としてのノードの 2 つのパラメータを受け取ります。ノードを挿入すると、挿入されたノードは参照ノードの前の兄弟ノードになります。同時にメソッドによって返されます。
replaceChild(): 挿入されるノードと置換されるノードの 2 つのパラメーターを受け取ります。置換されるノードはこのメソッドによって返され、ドキュメント ツリーから削除されます。同時に、その位置は挿入されるノードによって占められます。
removeChild(): 削除されるノードである 1 つのパラメーターを受け取ります。削除されたノードを返します。
これら 4 つのメソッドはすべて、操作されているノードの子ノードです。つまり、これらのメソッドを使用するには、まず親ノードを取得する必要があります。また、すべてのノードに子ノードがあるわけではありません。子ノードをサポートしていないノードでこれらのメソッドを呼び出すと、エラーが発生します。
appendChild() に渡されたノードが既にドキュメントの一部である場合、その結果、ノードは元の場所から新しい場所に移動されます。 。 DOM ツリーは接続された一連のポインターとして表示できますが、DOM ノードをドキュメント内の複数の場所に同時に表示することはできません。
在使用 replaceChild()插入一个节点时,该节点的关系指针都会从被它替换的节点复制过来。从技术上来讲,被替换的节点仍然还在文档中,但它在文档中已经没有了自己的位置。同样的, removeChild()移除的节点也同样为文档所有,只不过在文档中已经没有了自己的位置。
有两个方法是所有类型节点都要的。
cloneNode()
<ul> <li>item 1</li> <li>item 2</li> <li>item 3</li></ul>var myList = document.body.childNodes[1];var deepList = myList.cloneNode(true); //3 (IE < 9)或7(其他浏览器)console.log(deepList.childNodes.length);// 使用childNodes属性的建议for (var i =0; i < ele.childNodes.length; i++){ if(childNodes[i].nodeType === 1) { // 执行某些操作 }}
deepList.childNodes.length中的差异主要是因为IE8以及更早版本与其他浏览器处理空白字符的方式不一样。IE9以及之前版本不会为空白符创建节点。
cloneNode()方法不会复制添加到DOM节点中的Javascript属性,例如事件处理程序等。这个方法只复制特性,在明确指定的情况下也复制子节点,其他一切都不会复制。IE在此存在一个bug,即它会复制事件处理程序,所以建议,在复制之前最好先移除事件处理程序。
normalize()
Javascript通过Document类型表示文档。HTMLDocument继承自Document类型
1.document对象是HTMLDocument对象的实例2.document对象是window对象的一个属性,可以将其作为全局对象进行访问。
document instanceof HTMLDocument //trueHTMLDocument.__proto__ ==== Document //true
document作为我们操作文档的一个公共接口存在。
document.URL:包含页面完整的URL
document.domain:包含页面的域名
document.referrer:保存着链接到当前页面的那个页面的URL
在这三个属性中只有domain是可以设置的。但由于安全方面的限制,也并非可以给domain设置任何值。
不能将这个属性设置为URL中不包含的域
如果域名一开始是松散的,那么不能将它设置为紧绷的。
// 假设页面来自p2p.wrox.com域document.domain = 'wrox.com'; // 松散的,成功document.domain = 'nczonline.ne4t' // 出错document.domain = 'p2p.wrox.com' // 紧绷的,出错
document.readyState:有两个可能的值(HTML5新增)
loading:正在加载文档
complete:已经加载完文档
document.compatMode:这个属性的作用是告诉开发人员浏览器采用了那些渲染模式(HTML5新增)
值等于’CSS1Compat’,表明浏览器采用标准模式进行渲染
值等于’BackCompat’,表明浏览器在混杂模式下进行渲染
document.documentElement:获得html元素的引用
document.body:获得body元素的引用
document.head:获得head元素的引用(HTML5新增)
document.title:包含title元素的中的文本
document.activeElement:这个属性始终会引用DOM中当前获得了焦点的元素(HTML5新增)
Browser compatibility-head
Browser compatibility-activeElement
Document类型为查元素提供了两种方法,1,2
HTMLDocument类型提供了方法,3
document.getElementById()
document.getElementsByTagName():返回包含0或多个元素的NodeList。在HTML文档中,这个方法会返回一个 HTMLCollection对象,作为一个动态集合,该对象与NodeList非常相似。
document.getElementsByName:这个方法会返回带有给定name特性的元素,最常用于取得单选按钮。同样也返回 HTMLCollection对象。
HTMLCollection对象,可以通过length属性访问元素长度,通过[]方括号语法访问对象中的项。方括号中既可以是数字也可以是字符串的索引值。
document.createElement():接收一个参数,即要创建元素的标签名。
document.createTextNode():接收一个参数,要插入节点中的文本。
这些集合都是HTMLCollection对象
document.anchors:包含文档中带name特性的>元素
document.forms:包含文档中所有的
document.images:包含文档中所有的元素
document.links:包含文档中所有带href特性的a元素
Element类型用于表现HTML或XML元素。HTMLElement类型继承自Element类型。并添加了一些属性。
HTMLElement.__proto__ === Element// true
读取
添加的属性:可读也可写
lang(很少使用)
dir(很少使用)
className:与元素的class特性对应。
dataset:HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,目的是为元素提供与渲染无关的信息,或者提供语义信息。这些属性可以任意添加,随机命名,只要以data-开头即可。可以通过元素的 dataset属性来访问自定义属性
<div id="myDiv" class="bd" title="body text" lang="en" dir="ltr"></div> var div = document.getElementById('bd'); console.log(div.id); console.log(div.className); console.log(div.title); console.log(div.lang); console.log(div.dir);
相关方法
getAttribute():一般只有在取自定义特性情况下,才会使用此方法
setAttribute():接收两个参数,要设置特性的特性名和值
removeAttribute():用于彻底删除元素的特性
attributes属性
attributes属性中包含一个NamedNodeMap,与NodeList类似。
通常用于遍历元素的特性。
function outputAttributes ( ele ) { var pairs = [], attrName, attrValue, i, len; for(i = 0; i < ele.attributes.length; i++) { attrName = ele.attributes[i].nodeName; attrValue = ele.attributes[i].nodeValue; pairs.push(attrName + '=/' + attrValue + '/'') } pairs.join('');}
操作类名时,需要通过 className属性添加、删除、和替换类名。因为 className是一个字符串,所以即使只修改字符串一部分,也必须每次都设置整个字符串的值。
<div class="bd user disabled"></div> // 删除'user'类 // 首先取得类名字字符并拆分成数组 var div = document.getElementsByTagName('div')[0]; var className = div.className.split(//s+/); // 找到要删的类名 var pos = -1, i, len for(i = 0,len = className.length;i < len;i++) { if(className[i] === 'user') { pos = i; break; } } className.splice(i,1); // 把剩下的类名拼成字符串并重新设置 div.className = className.join(' ');
为了从div中删除class属性中的’user’,以上这些代码都是必须的。很多javascript都实现了这个方法,以简化这些操作
classList
HTML5新增了一个操作类名的方式,可以让操作更简单也更安全。那就是为所有元素添加classList这个属性。这个classList属性是新集合类型DOMTokenList的实例。这个属性是只读的,有一个表示自己包含多少元素的length属性,而要取得每个元素可以使用item()方法,也可以使用方括号语法。如果你想修改classList属性,那么可以通过它定义的以下几个方法进行修改。
add(value):将给定的字符串值添加到列表中。如果值已经存在,就不添加了
remove(value):从列表中删除给定的字符串
contain(value):表示列表中是否存在给定的值,如果存在则返回true,不存在返回false
toggle(value):如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它
Browser Compatibility
insertAdjacentHTML():接收两个参数,插入位置和要插入的HTML文本
第一个参数必须是下列值之一:
beforebegin:在当前元素之前插入一个紧邻的同辈元素
afterbegin:在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素
beforeend:在当前元素之下插入一个新的的子元素或在最后一个子元素之后插入新的子元素
afterend:在当前元素之后插入一个紧邻的同辈元素
浏览器兼容性
包含的是可以照字面意思接收的纯文本内容。
<!-- 没有内容,也就没有文本节点 --><div></div><!-- 有空格,因而有一个文本节点 --><div> </div><!-- 有内容,因而有一个文本节点 --><div>HELLO WORLD!</div>
DOM文档中存在相邻的同胞文本节点很容易导致混乱,因为分不清哪个文本节点表示哪个字符串。
浏览器在解析文档时,永远不会创建相邻的文本节点。
出现相邻的文本节点只会作为执行DOM操作的结果出现
如果在一个包含两个或多个文本节点的父元素上调用,Node类型的 normalize()方法,则会将所有文本节点合并成一个节点。
var ele = document.createElement('div');var text1 = document.createTextNode('Hello World!');var text2 = document.createTextNode('Hi');ele.appendChild(text1);ele.appendChild(text2);document.body.appendChild(ele)console.log(ele.childNodes.length);// 2ele.normalize();console.log(ele.childNodes.length);// 1
splitText():这个方法会将一个文本节点分成两个文本节点,即按照指定的位置分割nodeValue值。
var ele = document.createElement('div');var text = document.createTextNode('Hello World!');ele.appendChild(text);document.body.appendChild(ele)var newNode = ele.firstChild.splitText(5);console.log(newNode.nodeValue);// ' World'
// 创建tablevar table = document.createElement('table');table.border = 1;table.width = '100%';// 创建tbodyvar tbody = document.createElement('tbody');table.appendChild(tbody);// 创建第一行tbody.insertRow(0);tbody.rows[0].insertCell(0);tbody.rows[0].cells[0].appendChild(document.createTextNode('Cell 1.1'));tbody.rows[0].insertCell(1);tbody.rows[0].cells[1].appendChild(document.createTextNode('Cell 2.1'));// 创建第二行tbody.insertRow(1);tbody.rows[1].insertCell(0);tbody.rows[1].cells[0].appendChild(document.createTextNode('Cell 1.2'));tbody.rows[1].insertCell(1);tbody.rows[1].cells[1].appendChild(document.createTextNode('Cell 2.1'));// 添加到文档中document.body.appendChild(table);
可以通过Document类型和Element类型的实例调用他们。
querySelector()querySelectorAll()
Browser Compatibility-querSelector
Browser Compatibility-querSelectorAll不像如 getElementsByTagName这样的API, 通过以上两个API返回的对象不是live的。也就是说当文档改变的时候,他们不会改变。
具体来说,返回的值实际上是带有所有属性和方法的NodeList,而其底层实现则类似于一组元素的快照,而非不断对文档进行搜索的 动态查询。这样实现可以避免使用NodeList对象通常会引起的大多数性能问题
getElementsByClassName():返回NodeList对象,所以使用这个方法与使用 getElementsByTagName()以及其他返回NodeList的DOM方法具有同样的性能问题
Browser Compatibility
NodeList及其近亲NameNodeMap和HTMLCollection这个三个集合都是动态的。也就是说每当文档结构发生变化,他们都会得到更新。
本质上:NodeList对象是在访问DOM文档时实时运行的查询。
DOM操作往往是Javascript程序中开销最大的部分,而因访问NodeList导致的问题最大。一般来说,尽量减少访问NodeList的次数。因为每次访问NodeList,都会运行一次基于文档的查询。所以,可以考虑将从NodeList取得的值缓存起来。或者尽量减少DOM操作
对于元素间的空格,IE9以及之前不会返回文本节点,而其他所有浏览器都会返回文本节点。这样就导致了在使用childNodes和firstChild等属性时的行为不一致。为了弥补这一差异。
ElementTranversal API为DOM元素添加了以下5个属性
childElementCount:返回子元素(不包括文本节点和注释)的个数
firstElementChild:指向第一个子元素;firstChild的元素版
lastElementChild:指向最后一个子元素;lastChild的元素版
previousElementSibling:指向前一个同辈元素;previousSibling的元素版
nexrtElementSibling:指向后一个同辈元素;nextSibling的元素版
Browser Compatibility