DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口)。DOM描绘了一个层次节点树,允许开发人员添加、移除和修改。
1.节点层次
Simple Page Hello World!
如上的HTML文档,可以表示为一个层次结构。
文档元素:每个文档的根节点,即<html>元素。文档元素是文档最外层的元素,文档中其他元素都包含在文档元素中。每个文档只能有一个文档元素。在HTML页面中,文档元素始终都是<html>元素。在XML中,没有预定义的元素,因此任何元素都可以成为文档元素。
注意:Element titile->Text Simple Page。这个在dom节点操作的时候,不要将text这个节点忘记。
1.1Node类型
节点类型由Node类型中定义的下列数值常量白哦是,任何节点类型必居其一。
- Node.ELEMENT_NODE(1)
- Node.ATTRIBUTE_NODE(2)
- Node.TEXT_NODE(3)
- Node.CDATA_SECTION_NODE(4)
- Node.ENTITY_REFERENCE_NODE(5)
- Node.ENTITY_NODE(6)
- Node.PROCESSING_INSTRUCTION_NODE(7)
- Node.COMMENT_NODE(8)
- Node.DOCUMENT_NODE(9)
- Node.DOCUMENT_TYPE_NODE(10)
- Node.DOCUMENT_FRAGMENT_NODE(11)
- Node.NOTATION_NODE(12)
确定节点类型:
if(someNode.nodeType == Node.ELEMENT_NODE){ //在IE中无效,因为IE没有公开Node类型的构造函数 alert("Node is an element");}
if(someNode.nodeType == 1){ //适用于所有浏览器 alert("Node is an element");}
nodeName和nodeValue属性
if(someNode.nodeType == 1){ value = someNode.nodeName; //nodeName 的值是元素的标签名,因此需要先判断是否是元素}
NodeList:一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点,但是他并不是Array的实例,虽然这个对象也有length属性。NodeList对象的独特之处在于,它实际上是基于DOM结构动态执行查询结果,因此DOM结构的变化能够自动反映在NodeList对象中。
var firstChild = someNode.childNodes[0];var secondChild = someNode.childNodes.item(1);var count = someNode.childNodes.length;
someNode指的是父节点,childNodes指的是父节点下面所有的子节点,包括text。
将NodeList转换为数组,
//在IE8及之前版本中无效var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0);//兼容 function convertToArray(nodes){ var array = null; try{ array = Array.prototype.slice.call(nodes,0);//针对非IE浏览器 }catch(ex){ array = new Array(); for(var i=0,len=nodes.length;i
父节点与同胞节点
对于上述的每个childNodes都有同一个父节点,它们的parentNode属性都指向同一个节点。此外,包含在childNodes列表中的每个节点相互之间都是同胞节点。对于一个节点而言,它有previousSibling和nextSibling属性,对应前后两个节点。
2.操作节点
2.1appendChild(),用于向childNodes列表的末尾添加一个节点。更新完成以后将会返回更新节点。
注意:如果传入到appendChild()中的节点已经是文档的一部分了,那结果就是将该节点从原来的位置转移到新位置。
2.2insertBefore(),接受两个参数:要插入的节点和作为参照的节点。插入节点以后,被插入的节点会变成参照节点的前一个同胞节点(previousSibing),同时被方法返回。
//插入称为最后一个节点returnNode = someNode.insertBefore(newNode,null);alert(newNode === someNode.lastChild); //true //插入后成为第一个节点 var returnedNoe = someNode.insertBefore(newNode,someNode.firstChild); alert(returnedNode === someNode.newNode); //true alert(newNode === someNode.firstNode); //true //插入到最后一个子节点前面 returnedNode = someNode.insertBefore(newNode,someNode.lastChild); alert(newNode === someNode.childNodes[someNode.childNodes.length - 2]); //true
(注:根据《JavaSctipt语言精粹》的建议,将“==”改为“===”,有兴趣的可以看一下这本书,总共只有155页)
2.3replaceChild(),接受两个参数:要插入的节点和要替换的节点。要替换的节点将会被删除,而以上两种方法并不会删除节点。
使用replaceChild()插入一个节点时,该节点的所有关心指针都会从被它替换的节点复制过来。尽管从技术上将,被替换的节点仍然还在文档中占据位置。
2.4removeChild(),移除节点,这个方法接受一个参数,即要移除的节点。被移除的节点将成为方法的返回值。与replaceChild()一样,通过removeChild()移除的节点仍然为文档所有,只不过在文档中已经没有了自己的位置。
注意:以上方法必须先获得父节点parentNode,并不是所有类型的节点都有子节点,如果在不支持子节点的节点上调用了这些方法,将导致错误。
2.5cloneNode()用于创建调用这个方法的节点的一个完全相同的副本。
someNode.cloneNode(true/false);
true:表示执行深复制,即复制节点及其整个子节点树。
false:表示浅复制,即只复制节点本身。
这里需要注意的是:IE9之前的版本不会为空白符创建节点。还有一个IE中存在的bug就是,它会复制事件处理程序,所以这里建议在复制之前最好先移除事件处理程序。
3.Document类型
简单来说,在浏览器中,document用于表示HTML页面的最底层节点。可以直接使用它来获取页面上的任意节点。可以试着通过document.nodeChilds进行测试。在console中我们可以看到NodeList[2]……
Document节点的特征:
nodeType:9;nodeName:"#document";nodeValue:null;parentNode:null;ownerDocument:null;
子节点:DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或Comment。
3.1文档子节点
内置了两个访问其子节点的快速方式:documentElement,该属性始终指向HTML页面中<html>元素。另一个就是通过childNodes列表访问文档元素。
这里需要注意的是,一般情况下我们的页面开始是<!DOCTYPE html>,有这个在页面中时,document.childNodes获取的第一个是<!DOCTYPE html>,要通过childNodes遍历得到html元素是document.childNodes[1],使用从整个子节点获取需要看具体情况分析。
直接获取属性:
var body = document.body; //获取对的引用var doctype = document.doctype; //获取对的引用
浏览器对于document.doctype的支持不一致,因此这个属性并不常用。
同样还需要注意的是关于在html外面的注释是否是节点这个问题,不同的浏览器处理是不一样的。
3.2文档信息
//获取文档标题var originalTitle = document.title;//设置文档标题document.title = "New page title";//获取完整的URLvar url = document.URL;//获得域名var domain = document.domain;//获得来源页面的URLvar referrer = document.referrer;
URL、domain、referrer三个属性都和页面请求有关
document.URL>"http://www.cnblogs.com/lyhabc/p/6131034.html"document.domain>"www.cnblogs.com"document.referrer>"http://www.cnblogs.com/"
随便开个页面输出一下,我们可以看到三个属性的差别。
在这三个属性中,只有domain是可以设置的。但由于安全方面的限制,并非可以给domain设置任何值。
例如上面这个页面,只能写 document.domain = "www.cnblogs.com"/ document.domain = "cnblogs.com",由于跨域安全设置,来自不同子域的页面无法通过javascript通信,而通过将每个页面的document.domain设置为相同值,这些页面就可以相互访问对方的javascript对象了。
在内嵌框架中会使用到这个。(http://www.3lian.com/edu/2015/05-22/215443.html这个讲的比较粗浅明白)
3.3查找元素
这个是重点!!!!!!!
1.getElementById(),通过接收获取元素的ID来找到对应元素,这里的ID必须与页面中元素的id严格对应。
这里要注意的是:在IE7及更早的版本中并不区分id的大小写,还有如果页面中存在多个相同的id值,那么它会返回第一个出现的元素。
另一个问题是,表单字段的name特性,在IE7种通过getElementById()将会去与表单中name值进行匹配。因此最好不要让表单字段的name特性与其他元素的ID相同。
2.getElementsByTagName(),通过接受一个参数获取元素的标签名,返回的是包含零个或多个元素的NodeList。
这里有个“动态”集合的概念
例如,在页面中有多个div
var list = document.getElementsByTagName('div');console.log(list.length); //8document.body.appendChild(document.createElement('div'));
在浏览器中,直接输出list.length是9。
对于图像元素来说,还有以下方法。
var imges = document.getElementsByTagName("img");var myImage = images.namedItem("myImage");var myImage = images["myImage"]; imgaes[0].src; //输出第一个图像元素的src特性
3.getElemnetsByName() ,是只有HTMLDocument类型才有的,即返回带有给定name特性的所有元素。
常见案例是单选按钮,它们的name必须是一样的。对于单选按钮来说,namedItem()方法只会取得第一项。
4.其他集合,这些都是HTMLCollection对象
document.anchors,包含文档中所有带name特性的<a>元素
document.forms,包含文档中所有<form>元素
document.images包含文档中所有<img>元素
document.link,包含文档中所有带href特性的元素
5.DOM一致性检测
DOM分为多个级别,也包含多个部分。
document.implementation属性提供相应信息和功能
这里主要是使用hasFeature()进行版本检测
var hasXmlDom = document.implementation.hasFeature("XML","1.0");
通过返回的布尔值判断是否是对应版本。
这个功能并不常用,一般情况下,我们在使用一个属性判断是否可以在各种浏览其中使用时,可以直接使用通过try-catch来进行兼容。
3.6文档写入
write()、writelin()、open()、close()
write()会原样写入,writeln()会在字符串末尾添加换行符\n
这里需要注意的是,如果你在文档加载完成后使用了write()或writeln()写入,那么写入的内容将会重新整个页面。
它们可以进行HTML代码的处理,也可以写入<script>只是需要转义符。
4.Element类型
Element类型用于表现XML或HTML元素,提供了对元素标签名、子节点及特性的访问。Element节点具有以下特征:
nodeType 的值为1
nodeName 的值为元素的标签名;
nodeValue 的值为null;
parentNode 可能是Document或Element;
nodeName和tagName用于访问元素的标签名
<div id="myDiv"></div>
var div = document.getElementBId("myDiv");
alert(div.tagName);//"DIV"
alert(div.tagName === div.nodeName);//true
在HTML中,表签名始终以大写表示;而在XML中(有时候也包括XHTML)中,标签名始终与源代码中的保持一致。
所以要比较的时候最好使用:
if(element.tagName.toLowerCase() === "div"){}
4.1HTML元素
id,元素在文档中唯一标识符。
title,有关元素的附加说明,一般通过工具提示条显示出来。
lang,元素内容的语言代码,很少使用。
dir,语言方向,值为“ltr”(left-to-right,从左至右)或“rtl”(right-to-left,从右至左),也很少使用。
className,与元素class特性对应,即为元素指定的CSS类。没有将这个属性命名为class,是因为class是ECMAScript的保留字。
(这里插一条,在IE8及以下,无法使用getElementsByClassName()获取对应的元素,因此通过className进行兼容)
var div = document.getElementById("myDiv");div.id //"myDiv"div.className //"bd"div.title //"Body text"div.lang //"en"div.dir //"ltr"
同时也可以进行修改
div.id = "somOtherId";div.className = "ft";div.title = "Some other text";div.lang = "fr";div.dir = "rtl";
操作特性的DOM三个主要方法:getAttribute()、setAttribute()、removeAttribute()
4.2取得特性,getAttribute()
var div = document.getElementById("div");alert(div.getAttribute("id")); //"myDiv"alert(div.getAttribute("class"));alert(div.getAttribute("title"));alert(div.getAttribute("lang"));alert(div.getAttribute("dir"));
注意:传递给getAttribute()的特性名与实际的特性名相同。因此要想得到class特性值,应该传入“class”而不是“className”,后者只有在通过对象属性访问特性的时候才使用。
可以使用自定义特性,同时特性名词不区分大小写。
根据HTML5规定,自定义特性应该加上data-前缀以便验证,实际浏览器不添加该前缀并不会报错,但是最好按照标准来。
对于HTML中公认的特性,该元素的DOM对象也将存在对应的属性。
对于特殊的存在:style和onclick类似事件处理程序
通过getAttribute()访问时,返回的style特性值中包含css文本,而通过属性来访问它则会返回一个对象。注意,这里是指的内联样式。
document.getElementById("d").getAttribute("style"); >"backgroundColor:red;font-size:10px;"document.getElementById("d").style;>CSSStyleDeclaration {0: "font-size", alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", all: ""…}
onclick这样的事件处理程序。当在元素上使用时,通过getAttribute()访问,则会返回相应代码的字符串。而在访问onclick属性时,则会返回一个JavaScript函数。
一般不建议获取HTML公认特性的时候使用getAttribute(),而是使用对象属性。
4.3设置特性
div.setAttribute("id","someOtherId");div.setAttribute("class","ft");div.setAttribute("title","Some other text");div.setAttribute("lang","fr");div.setAttribute("dir","rtl");
这个方法既可以操作HTML特性也可以操作自定义特性,而div.id = "someOtherId"这种方法不可以操作自定义特性。
4.4removeAttributes()
这个方法用于彻底删除元素的特性。调用这个方法不仅会清除特性的值,而且也会从元素中完全删除特性。
4.5document.createElement()创建新元素
var div = document.createElement("div");
创建完成以后,可以痛过操作元素特性添加更多子节点以及其他操作。
div.id = "myNewDiv";
div.className = "box";
通过appendChild()、insertBefore()、replaceChild()方法,添加到文档树中。
在IE7以及更早的版本中,有以下已知问题:
不能设置动态创建的<iframe>元素的name特性。
不能通过表单的reset()方法重设动态创建的<input>元素。
动态创建的type特性值为“reset”的<button>元素重设不了表单。
动态创建的一批name相同的单选按钮彼此毫无关系。
这些问题可以通过createElement()中指定完整的HTML标签来解决。
if(client.browser.ie && client.browser.ie<=7){ //创建一个带有name特性的iframe元素 var iframe = document.createElement(""); //创建input元素 var input = document.createElement(""); //创建button元素 var button = document.createElement(""); //创建单选按钮 var radio1 = document.createElement("
5.关于元素的子节点的差别childNode获得的节点
- Item 1
- Item 2
- Item 3
在IE中,<ul>元素会有3个子节点,分别是3个<li>元素。但如果是在其他浏览器中,<ul>会有7个元素,包括3个<li>元素和4个文本节点(包括<li>元素之间的空白符)
通过childNodes属性遍历nodeType属性,需要element.childNodes[i].nodeType === 1,判断一下。
6.Text类型
nodeType的值为3;
nodeName的值为“#text”;
nodeValue的值为节点所包含的文本;
parentNode是一个element;
不支持(没有)子节点。
在默认情况下,一个元素最多只能包含有一个文本系欸但,而且必须确实存在内容。
var textNode = div.firstChild;//获取文本节点
div.firstChild.nodeValue = "Some other message"; //修改文本节点中nodeValue内容
div.firstChild.nodeValue = "Some <strong>other</strong> message";
输出结果是"Some <strong>other</strong> message";
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
本来标题应该是【JavaScript整理】,想要整理的稍微规范并且全面些,拿出了“尘封已久”的《JavaScript高级程序设计》,然后在强迫症的作用下一发不可收拾成了笔记摘录了。这本书还是强烈推荐都看看的,虽然很厚,不过有时候弯路才是真正的捷径,在对学习前端开始入门并且感兴趣以后,可以回归书本一下。
顺便推荐本书:《CSS禅意花园》