**DOM面向对象** **,低版本IE 中的所有 DOM 对象都是以 COM对象的形式实现的。这意味着 IE 中的DOM 对象与原生 JavaScript 对象的行为或活动特点并不一致。这些差异需要注意。** - DOM节点的层次 - Node类型 - Document类型 - Element类型 - Text类型 - DocumentFragment类型 - Attr类型 # DOM节点的层次 DOM是树形的结构, Document

hello word

DOM的结构如下 ![](http://i.imgur.com/tY1ymHt.png) 节点间的各种关系可以用传统的家族关系来描述,相当于把文档树比喻成家谱。在 HTML 中,可以将 元素看成是 元素的子元素;相应地,也就可以将 元素看成是 元素的父元素。而 元素,则可以看成是 元素的同胞元素,因为它们都是同一个父元素 的直接子元素。 # Node类型 DOM 可以将任何 HTML 或 XML 文档描绘成一个由多层节点构成的结构。节点分为几种不同的类型,每种类型分别表示文档中不同的信息及(或)标记。每个节点都拥有各自的特点、数据和方法,另外也与其他节点存在某种关系。节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的树形结构 文档节点只有一个子节点,即 元素,我们称之为**文档元素**。文档元素是文档的最外层元素,文档中的其他所有元素都包含在文档元素中。每个文 档只能有一个文档元素。在 HTML 页面中,文档元素始终都是 元素。在 XML 中,没有预定义的元素,因此任何元素都可能成为文档元素。 每一段标记都可以通过树中的一个节点来表示:HTML 元素通过元素节点表示,特性(attribute)通过特性节点表示,文档类型通过文档类型节点表示,而注释则通过注释节点表示。总共有 12 种节点类型(nodeType),这些类型都继承自一个基类型。

hello word

hello word

hello word

hello word

可以输出看下Node上面的属性和方法; ![](http://i.imgur.com/8Rc7GSh.png) 重点关心下面几个**属性**; - nodeType 节点类型 - nodeName 节点名称 - nodeValue 节点值 - childNodes 获取所有的子节点 - children 获取所有的元素子节点 - firstChild 获取第一个子节点(不一定是元素节点) - lastChild 获取最后一个子节点 - nextSibling 获取下一个弟弟节点(不一定是元素节点) - previousSibling 获取上一个哥哥节点 - parentNode 获取父亲节点 Node上面的**方法** - appendChild 将节点添加到指定容器的最后面 - insertBefore 将新的节点添加到指定容器中某一个节点的前面 - replaceChild 把原有的元素进行替换 - removeChild 删除元素 - cloneNode 复制原有的节点,如果传递的值是true,代表将子子孙孙的后代元素一起赋值,false代表只复制当前元素本身 - hasChildNodes 返回一个布尔值,表明当前节点是否包含有子节点. - normalize DOM1 级定义了一个 Node 接口,该接口将由 DOM 中的所有节点类型实现。这个 Node 接口在JavaScript 中是作为 Node 类型实现的;除了 IE 之外,在其他所有浏览器中都可以访问到这个类型。JavaScript 中的所有节点类型都继承自 Node 类型,因此所有节点类型都共享着相同的基本属性和方法。 ### Node的属性 ##### nodeType / nodeName / nodeValue NodeType 有以下几种;但是并不需要都记住的; - ELEMENT_NODE:1 - ATTRIBUTE_NODE:2 - TEXT_NODE:3 - CDATA_SECTION_NODE:4 - ENTITY_REFERENCE_NODE:5 - ENTITY_NODE:6 - PROCESSING_INSTRUCTION_NODE:7 - COMMENT_NODE:8 - DOCUMENT_NODE:9 - DOCUMENT_TYPE_NODE:10 - DOCUMENT_FRAGMENT_NODE:11 - NOTATION_NODE:12 在JS中常用的只有几个,元素节点,文本节点,注释节点,document,他们对应的值是 名次 数字 nodeName的值 nodeValue的值 元素节点 1 大写的标签名 null 文本节点 3 #text 文本内容 注释节点 8 #comment 注释内容 document 9 #document null > 如果四个还记住,记住一个元素节点就可以了;(元素节点 ELEMENT_NODE:1,) 在标准浏览器中会把空格,Enter当作文本节点; if (someNode.nodeType == 1){ // 适用于所有浏览器,注意不要用Node.ELEMENT_NODE进行比较,在低版本IE中不兼容; console.log("Node is an element."); } **nodeName 和 nodeValue ** 这两个属性。这两个属性的值完全取决于节点的类型。在使用这两个值以前,最好是像下面这样先检测一下节点的类型。 if (someNode.nodeType == 1){ testNodeName = someNode.nodeName; //nodeName 的值是元素的标签名 testNodeValue = someNode.nodeValue; //nodeValue 的值是null } 在这个例子中,首先检测节点类型,看它是不是一个元素,如果是则取得并保存nodeName的值,对于元素节点nodeName中保存的始终都是元素的标签名,而nodeValue的值则始终为null; ##### childNodes

hello word1

hello word2

hello word3

hello word4

每个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象。 NodeList 是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。请注意,虽然可以通过方括号语法来访问 NodeList 的值,而且这个对象也有 length 属性,但它并不是 Array 的实例。 上面例子展示了如何访问保存在 NodeList 中的节点——可以通过方括号,也可以使用 item()方法 , 个人喜欢用方括号。 > 注意 length 属性表示的是访问 NodeList 的那一刻,其中包含的节点数量,如果改变之后,再次访问它的length,会看到变化。 //检测数据类型 console.log({}.toString.call(selectAll));//[object HTMLCollection] //类数组转为真正的数组 var arrayOfNodes = Array.prototype.slice.call(selectAll); console.log(arrayOfNodes); console.log({}.toString.call(arrayOfNodes));//[object Array] 上面的方法IE678不兼容, //类数组转为真正的数组,兼容写法 function convertToArray(nodes){ var array = []; try { array = Array.prototype.slice.call(nodes, 0); //针对非 IE 浏览器 } catch (e) { for (var i= 0,len=nodes.length; i < len; i++){ array.push(nodes[i]); } } return array; } var arrayOfNodes = convertToArray(selectAll); console.log({}.toString.call(arrayOfNodes));//[object Array] ** childNodes需要注意的(元素的子节点方法;)** 看下面的代码 myList1的childNodes是7,myList2的chilNodes是3;(myList1里面有Text 类型) 如果在myList1中获取全部的li,可以直接用getElementByTagName; var test1=document.getElementById("myList1"); var lis=test1.getElementsByTagName("li"); console.log(lis); 这样就拿到了,先确定范围,然后通过标签名来获取;还可以判断元素的是否为原来来获取 var test1=document.getElementById("myList1"); var ary=[]; for(var i=0,len=test1.childNodes.length;i
Hello World!
上面代码给出的第一个
元素没有内容,因此也就不存在文本节点。开始与结束标签之间只要存在内容,就会创建一个文本节点。因此,第二个
元素中虽然只包含一个空格,但仍然有一个文本子节点;文本节点的 nodeValue 值是一个空格。第三个
也有一个文本节点,其 nodeValue 的值为 "Hello World!" 。 ##### parentNode、firstNode、lastNode、nextSibling、previousSibling DOM结构如下

hello word1

hello word2

hello word3

hello word4

![](http://i.imgur.com/9p097e3.png) 总结: - 1、父节点的 firstChild 和 lastChild属性分别指向其 childNodes 列表中的第一个和最后一个节点。firstChild等于childNodes[0],lastChild原理一样; - 2、在只有一个子节点的情况下, firstChild 和lastChild 指向同一个节点。如果没有子节点,那么 firstChild 和 lastChild 的值均为 null 。 - 3、如果列表中只有一个节点,那么该节点的 nextSibling 和 previousSibling 都为 null ### Node的方法 - appendChild - insertBefore - replaceChild - cloneNode - hasChildNodes ##### appendChild 将节点添加到指定容器的最后面,返回新增的节点。

hello word1

hello word2

hello word3

hello word4

参考:[https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild) ##### insertBefore 将新的节点添加到指定容器中某一个节点的前面,方法接受两个参数:要插入的节点和作为参照的节点。 var insertedNode = parentNode.insertBefore(newNode, referenceNode); 插入节点后,被插入的节点会变成参照节点的前一个同胞节点( previousSibling ),同时被方法返回。 如果参照节点是null ,则 insertBefore() 与 appendChild() 执行相同的操作 https://developer.mozilla.org/en-US/docs/Web/API/Node/insertbefore ##### replaceChild 把原有的元素进行替换 replacedNode = parentNode.replaceChild(newChild, oldChild); - 如果newChild已经存在于DOM树中,首先会被删除; - oldChild会被newChild所取代,olcChild是被替换掉的原始节点 - replacedNode ##### cloneNode 赋值节点 var dupNode = node.cloneNode(blooeanValue); - node是被赋值的节点 - dupNode是赋值后的文件; - blooeanValue 是否采用深度克隆 - 如果为true,则该节点的所有后代节点也都会被克隆 - 如果为false,则只克隆该节点本身. - 虽然 blooeanValue是可选的参数,但是推荐当做必须参数用; 备注: - 克隆一个元素节点会拷贝它所有的属性以及属性值,当然也就包括了属性上绑定的事件(比如onclick="alert(1)"),但不会拷贝那些使addEventListener()方法或者node.onclick = fn这种用JavaScript动态绑定的事件. - 推荐:平时写代码的时候,用事件委托的方式去写代码; - **clonenode()可能导致文件重复的元素ID**,如果原始节点设置了ID,并且克隆节点会被插入到相同的文档中,那么应该更新克隆节点的ID以保证唯一性。name属性可能也需要进行修改 - 想要克隆一个节点来添加到另外一个文档中,请使用Document.importNode()代替本方法. ##### removeChild 该方法从指定的DOM结构中,删除一个子元素;返回值是要删除的节点;

hello word1

hello word2

hello word3

hello word4

- oTest1和parent1是父子节点的关系; - returnValue===oTest1, - 如果要删除的和被删除的节点不是父子关系,会报错 - 子元素不存在:parameter 1 is not of type 'Node'. - 要删除的子元素,不是父元素内的子元素:The node to be removed is not a child of this node. 参考:[https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild](https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild) ##### hasChildNodes 返回一个布尔值,表明当前节点是否包含有子节点. > 语法:element.hasChildNodes() > 注意:Node.hasChildNodes是个方法,而不是普通属性,使用时必须加括号才能调用. var foo = document.getElementById("foo"); if ( foo.hasChildNodes() ) { foo.removeChild( foo.childNodes[0] ); } 如果id为foo的这个元素有子节点,则从dom树中删除它的第一个子节点. # Document类型 - 查找元素 - 特殊集合 - 文档写入 - 文档的子节点 - 文档信息 - DOM一致性检测 输出document,查看有哪些属性和方法; console.dir(document); ### 查找元素 查看 Document 上的方法,最常用的就是查找元素的方法了;document的意思是整个页面的 console.log(document) 输出看一下; - getElementById - getElementsByClassName - getElementsByName - getElementsByTagName - querySelector - querySelectorAll ###### document.getElementById() **在整个文档中,通过元素的ID获取这个元素的对象,如果页面中没有这个ID,则获取的内容为null;** 需要注意的 > getElementById这个方法的写法,不能改变大小写; > document.getElementById("id"); 前面的范围,必须是document; > id是大小写敏感的字符串,代表了所要查找的元素的唯一ID.element是一个元素的,一个,找到的也是第一次找到id的所在元素; > getElementById方法不会搜索不在文档中的元素。当创建一个元素,并且分配ID后,你必须要使用insertBefore或其他类似的方法把元素插入到文档中之后才能使用 getElementById 获取到:如果不插入文档中,属于游离状态,此时获取是获取不到的; var element = document.createElement("div"); element.id = 'testId'; console.log(document.getElementById('testId'));//null document.body.appendChild(element); console.log(document.getElementById('testId'));//

hello word1

hello word2

hello word3

hello word4

###### document.getElementsByClassName() **在整个文档中,通过元素class样式类的值来获取一组元素,IE678不兼容** var elements = document.getElementsByClassName(names); // or: var elements = rootElement.getElementsByClassName(names); - elements 是复数,多个class的意思,查找到的所有元素的集合 HTMLCollection .返回的是一个类数组,如果找到某一个class,可以借助前面的范围,并且[0],这样的方式来确定某一个元素; - names 是一个字符串,表示用于匹配的 class 名称列表; 多个 class 名称通过空格分隔 - getElementsByClassName 可以在任意的元素上调用,不仅仅是 document。 调用这个方法的元素将作为本次查找的根元素(范围); ###### document.getElementsByTagName() **在整个文档中,通过元素的标签名来获取一组元素(HTMLcollection集合),获取的是一个类数组,获取的个数可以通过length获取,获取集合的某一个元素,通过对象的索引即可查找;** 即使一个文档里面,只有一个元素集合;这个元素也需要用[0]的方式给选出来,否则操作的是一个类数组; ###### document.getElementsByName() **在整个文档中,通过元素的name值来获取一组元素(NodeList集合),在IE浏览器中,此方法只对表单元素起作用;**

hello word1

hello word2

hello word3

hello word4
###### document.querySelector() 在整个文档中,通过不同的选择器获取一个元素对象,IE678不兼容 ###### document.querySelectorAll() 在整个文档中,通过不同的选择器获取一组元素对象集合,IE678不兼容; ###### document.documentElement 获取整个HTML对象 ###### document.body 获取整个body对象 ### 特殊集合 除了属性和方法,document对象还有一个特殊的集合,这些集合都是HTMLCollection对象,为了访问文档常用的部分提供的快捷方式; 正常工作中,很少直接这么用的; - document.anchors 包含文档中所有带name特性的元素; - document.links 包含文档中所有带href特性的元素, - document.forms 包含文档中所有带form的元素,与document.getElementsByName("form")相同; - document.imges 包含文档中所有带的元素,与document.getElementsByName("img")相同; ### 文档写入 将输出流写入到网页中,有4个方法; - write(string) 原样写入 - writeIn(string) 在字符串的末尾添加一个换行符(\n); - open() - close() write和writeIn Document

now time is:

open()和close()分别用于打开和关闭网页的输出流;如果是加载期间使用write()或者writeIn()方法,则不需要用到这两个方法; ### 文档的子节点 - document.documentElement;//拿到这个标签; - document.body//拿到body这个层的标签; 主要就是这两个方法的,当然也可以用别的方法来获取同样的效果的; 比如 document.childNodes[0]; document.firstChild; 这两个都可以获取到html标签; ### 文档信息 - document.title 设置文档的标题 - document.URL 获取或者设置完整的URL - document.domain 获取或者设置域名 - document.referrer 取得来源页面的URL ### DOM一致性检测 - hasFeartrue() # Element类型 - HTML元素 - 操作特性 - attributes属性 - 创建元素 Element和Document类型一样,都是非常使用的类型; Element的类型,nodeType的值为1、nodeName为元素的标签名,nodeValu是null;如果要访问元素的标签名,可以使用nodeName属性,也可以使用tagName属性;两个属性返回相同的值;
这是一个ID为test的div内容
返回的标签名是大写的DIV;一般比较都会转成小写然后比较;如下; if(test.tagName.toLowerCase()=="div"){ console.log("目标的元素是div标签,开始执行代码"); } ### HTML元素 所有的HTML元素都是由HTMLElement类型表示,如果不是直接通过这个类型,也是通过它的子类型表示;可以输出看下,HTMlElement类型继承自ELement类型的;
这是一个ID为test的div内容
输出的图片的如下; ![](http://i.imgur.com/Mto2IWP.png) 每个HTML元素都存在下面的标准特性 - id 元素在文档中的唯一标识符 - title 有关元素的附加说明信息,鼠标放上去会显示,(以前我以为只有a标签才有,其实是都有的) - lang 元素内容的语言代码,很少使用 - dir 语言的方向,值为ltr或者rtl,很少使用(left-to-right和right-to-left);rtl可以起到右对齐的效果; - className 与元素的class特性对应,是元素指定的CSS类,没有将这个属性命名为class,是因为class是ECMAscript的保留字;【*】
这是一个ID为test的div内容!!!ddddd.

这是一段文字

### 操作特性 - getAttribute() - setAttribute() - removeAttribute() **getAttribute**: var test=document.getElementById("test"); console.log(test.getAttribute("id"));//test console.log(test.getAttribute("className"));//null console.log(test.getAttribute("class"));//test-class-name console.log(test.getAttribute("title"));//鼠标放上来的提示 console.log(test.getAttribute("lang"));//en console.log(test.getAttribute("dir"));//rtl(最后一个字符不能是符号,否则符号在前面显示) console.log(test.getAttribute("diy-data"));//hehe 这个属性要注意的是,如果想获取到属性,必须先取得这个属性所在的元素;然后再进行相关的Attribute操作;这个属性可以获得自定义属性,根据HTML5规范,自定义的特性应该加上data-前缀进行验证; 转给getAttribute的特性名,与实际的特性名相同,因此要想得到class特性值,应该传入class而不是calssName; 但是有两类特殊的特性,虽然有对应的属性名,但是属性的值与通过getAttribute返回的不同; - 1、style - 2、onclick Document
这是一段测试文字;
通过JS操作DOM的时候,一般不适应getAttribute,而是只使用对象的属性,在取得自定义特性质的情况下,才会使用getAttribute的方法; **setAttribute**: 接受两个参数,第一个参数是特性名,第二个参数是特性值;如果特性已经存在,setAttribute会以指定的值替换现有的值;如果没有的值会创建并且新增; 通过这个方法设置的特性名会被统一转换为小写的形式;"ID"会最终变成id,"CLASS"会被变为"class"; var test=document.getElementById("test"); test.setAttribute("CLASS","dddddd");//class="dddddd" **removeAttribute**: 彻底删除元素的特性,调用这个方法不仅清除特性的值,而且也会从元素中完全删除特性;(IE6不支持) ### 创建元素, document.creatElement()方法,可以创建新元素,接受一个参数,就是要创建的元素,参数可以是标签名 - div 一般都使用标签名; 创建的元素属于游离状态,还没有被添加到文档树中,因为新建的元素并不会马上看到,可以使用appendChild,inserBefore,replaceChild()方法, var test=document.getElementById("test"); var creatEle=document.createElement('p'); creatEle.id="test-id"; creatEle.className="class-test"; creatEle.innerHTML="innerHTML"; test.appendChild(creatEle); ** 借助createDocumentFragment创建元素 ** 文档碎片;document fragment在文档没有对应的标记,为了赋值大量数据渲染时的一种节约性能方法; 原理是:创建大量元素的时候,把元素都先放在文档碎片里,等元素创建添加完,把文档碎片统一插入到指定的元素中; > 类似与我们生活中,发快递的时候,快递公司通过三轮车把所有的件搜收集起来,然后再统一拉回仓库去发件; 代码如下:
    # Text类型的方法 - document.createTextNode() 创建新文本节点 - normalize() 相邻文本节点合并 - splitText() 分割文本节点 **document.createTextNode()** 创建新文本节点,接收一个参数,要插入节点中的文本,(作为参数的文本将按照HTML或者XML的格式进行编码) var ele=document.createElement("div"); var textNode=document.createTextNode('hello word'); var anotherTextNode = document.createTextNode("lee!"); ele.className="message"; ele.appendChild(textNode); ele.appendChild(anotherTextNode); document.body.appendChild(ele); 如果两个文本节点是相邻的同胞节点,那么这两个节点中的文本就会连起来显示,中间不会有空格。 **normalize** 如果在一个包含两个或多个文本节点的父元素上调用 normalize() 方法,则会将所有文本节点合并成一个节点,结果节点的 nodeValue 等于将合并前每个文本节点的 nodeValue 值拼接起来的值。 var ele=document.createElement("div"); var textNode=document.createTextNode('hello word'); var anotherTextNode = document.createTextNode("lee!"); ele.className="message"; ele.appendChild(textNode); ele.appendChild(anotherTextNode); document.body.appendChild(ele); console.log("childNodes的长度:"+ele.childNodes.length+",第一个节点值是"+ele.firstChild.nodeValue);//childNodes的长度:2,第一个节点值是hello word ele.normalize(); console.log("childNodes的长度:"+ele.childNodes.length+",第一个节点值是"+ele.firstChild.nodeValue);//childNodes的长度:1,第一个节点值是hello wordlee! **splitText()** 和normalize()相反的方法;按照指定的位置分割 nodeValue 值。 - 原来的文本节点将包含从开始到指定位置之前的内容;(不包含所传的索引) - 新文本节点将包含剩下的文本。 var ele=document.createElement("div"); var textNode=document.createTextNode('hello word'); ele.className="message"; ele.appendChild(textNode); document.body.appendChild(ele); console.log("childNodes的长度:"+ele.childNodes.length+",第一个节点值是"+ele.firstChild.nodeValue);//childNodes的长度:2,第一个节点值是hello word var newNode=ele.firstChild.splitText(2); console.log(ele.childNodes.length);//2 console.log(ele.firstChild.nodeValue);//he console.log(newNode.nodeValue);//llo word # 精华总结 - tagName 获取元素标签的名称 - className 获取或者设置元素class属性的值 -
    - 可以通过className获取test1,也可以把这个值进行修改; - oDiv.className="test2",此时div的calss就变为test2了,注意,这里的修改会覆盖原来的所有属性; - style 获取或者设置元素的行内样式,在获取的时候要注意,只能获取行内上写的样式,非行内样式不能获取; - oDiv.style.backgroundColor="red";就是设置元素的行内北京颜色是红色; - window.getComputerStyle 获取元素所有经过计算的样式(只要在页面中显示出来,那么该元素的样式都是经过计算的)这个方法,不兼容,一般是下面这种处理 - window.getComputerStyle?window.getComputedStyle(ele,null)[attr]:ele.currenStyle[attr] - document.creatElement() 创建一个元素节点,例如document.creatElement("div")就是创建一个div元素 - document.creatDocumentFragment() 创建文档碎片