Javascript之DOM

1 DOM

DOM重点:

  • 理解包含不同层次节点的DOM
  • 使用不同的节点类型
  • 克服浏览器兼容性问题及各种陷阱

DOM:文档对象模型[Document Object Model],提供访问和操作页面网页内容的方法和接口,DOM可以把HTML看做是文档树,通过DOM提供的API可以把树上的节点进行操作。DOM是针对HTML和XML文档的一个API(应用程序编程接口)。

  • DOM1级,有两个模块组成:DOM核心(DOM Core)和DOM HTML。DOM HTML是在DOM核心上扩展,增加了HTML的对象和方法。
  • DOM2级,增加模块:DOM视图、DOM事件、DOM样式、DOM遍历和范围。
  • DOM3,引入了以统一方式加载和保存文档的方法,在DOM加载和保存模块中定义、新增验证文档的方法、DOM核心进行扩展,支持XML1.0规范,涉及XML Infoset、XPath、XML Base。

1.1 节点层次

DOM:将任何XML或HTML文档描绘成一个由多层节点构成的结构。节点分为几种不同的类型,每种类型分别表示文档中不同的信息及标记。每一段标记都可以通过树中的一个节点来表示:HTML元素通过元素节点表示,特性(attribute)通过特性节点表示,文档类型通过文档类型节点表示,而注释则通过注释节点表示,总共有12种节点类型,这些类型都继承自一个基类型。

 

1 Node类型

DOM1定义了一个Node接口,该接口将由DOM中的所有节点类型实现。

//节点类型由在Node类中定义的下列12个数值常量来表示
Node.ELEMENT_NODE(1); // 元素节点
Node.ATTTRIBUTE_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);// 节点

eg1:
//IE不兼容,确定节点类型
if (somenode.nodeType == Node.ELEMENT_NODE){
    alert("Node is an element");
}
eg2:
//适用于所有浏览器,确定节点类型
if (somenode.nodeType == 1){
    alert("Node is an element");
} 
//1.nodeName和nodeValue属性,完全取决于节点的类型
if (somenode.nodeType == 1){
      value = somenode.nodeName;//判断是否为元素[元素节点:保存的是元素始终是标签名],nodeValue属性始终为null。
}

A Node之间的节点关系

文档中所有的节点之间都存在不同的关系。

每个节点都有一个childNodes属性,保存一个NodeList对象[NodeList是一种类型数组对象,用于保存一组有序的节点,通过位置进行访问]。

每个节点还有一个parentNode顺序,该属性指向文档树中的父节点。

所有节点都有最后一个属性是ownerDocument,该属性指向表示整个文档的文档节点。

//访问NodeList中的节点,可以通过方括号,也可以使用item()方法。
var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var secondChild = someNode.childNodes.length;//节点数量

//每个节点都有一个parentNode属性,指向文档树中的父节点。包含在childNodes列表中的所有节点都具有相同的父节点,包含在列表中的每个节点相互之间都是同胞节点。
//previousSibling[列表中第一个节点]、nextSibling[列表中最后一个节点]属性,可以访问同一列表中的其他节点。previousSibling=null,nextSibling=null
if (someNode.nextSibling === null){
   alert("Last node in the parent's childNodes list."); 
}else if (someNode.previousSibling=== null){
   alert("First node in the parent's childNodes list."); 
}

 

B Node之间的操作节点

关系指针都是只读的,DOM提供了一些操作节点的方法。

  1. appendChild()节点:插入节点,用于向ChildNodes列表的末尾添加一个节点。 添加节点后,childNodes的新增节点、父节点、以前的最后一个子节点的关系指针都会相应地得到更新。更新完成后,appendChild()返回新增的节点。
  2. insertBefore()节点:插入节点,接收2个参数[要插入的节点、作为参照的节点]。把节点放在childNodes列表中某个特定的位置上,而不是放在末尾。插入节点后,被插入的节点会变成参照节点的前一个同胞节点(previousSibling),同时被方法返回。如果参照节点为null,则与appendChild()执行相同的操作。
  3. replaceChild()节点:替换节点,接收2个参数[要插入的节点、要替换的节点]。要替换的节点将由这个方法返回并从文档树中被移除,同时由要插入的节点占据其位子。
  4. removeChild()节点:移除节点,接收一个参数[要移除的节点],被移除的节点将成为方法的返回值。
  5. cloneNode():用于创建调用这个方法的节点的一个完全相同的副本。接收一个布尔值参数,表示是否执行深复制。[true为深复制,false为浅复制]。
  6. normalize():处理文档树中的文本节点。

深复制:复制节点及其整个子节点数。

浅复制:只复制节点本身。复制后返回的节点副本属于文档所有,但并没有为它指定父节点。

eg1:
//DOM树看成是一系列指针连接起来的,但任何DOM节点也不能同时出现在文档中的多个位置上。
//appendChild(),用于向childNodes列表的末尾添加一个节点。
var returnedNode = someNode.appendChild(newNode);
alert(returnedNode  == newNode);   //true
alert(someNode.lastChild == newNode); //true

//appendChild(),从原来的位置转移到新位置。
//appendChild()传入了父节点的第一个节点,该节点就会成为父节点的最后一个子节点。
var returnedNode = someNode.appendChild(someNode.firstChild);
alert(returnedNode  == someNode.firstChild);   //false
alert(someNode.lastChild == someNode.lastChild); //true

eg2:
//someNode有多个子节点,放在特定的位置上,不是末尾,使用insertBefore()方法。
//insertBefore()方法,接受2个参数:要插入的节点和作为参照的节点。
//insertBefore(),插入后成为最后一个子节点
returnedNode = someNode.insertBefore(newNode,null);
alert(newNode== someNode.lastChild);   //true

//insertBefore(),插入后成为第一个子节点
returnedNode = someNode.insertBefore(newNode,someNode.firstChild);
alert(returnedNode == newNode);   //true
alert(newNode== someNode.firstChild);   //true

//insertBefore(),插入到最后一个子节点前面
returnedNode = someNode.insertBefore(newNode,someNode.lastChild);
alert(newNode== someNode.childNodes[someNode.childNodes.length-2]);   //true

eg3:
//replaceChild()接收2个参数:要插入的节点和要替换的节点。要替换的节点将由这个方法返回并从文档树中移出,同时由要插入的节点占据其位置。
//replaceChild(),替换第一个子节点
var returnedNode = someNode.replaceChild(newNode,someNode.firstChild);

//replaceChild(),替换最后一个子节点
var returnedNode = someNode.replaceChild(newNode,someNode.lastChild);

eg4:
//removeChild(),移除节点,接收一个参数:移除的节点。
//removeChild(),移除第一个子节点
var formerFirstChild= someNode.removeChild(newNode,someNode.firstChild);

//replaceChild(),移除最后一个子节点
var formerLastChild= someNode.removeChild(newNode,someNode.lastChild);

eg5:
//cloneNode(),用于创建调用这个方法的节点的一个完全相同的副本。true深复制,false浅复制。复制后返回的节点副本属于文档所有,但并没有为它指定父节点。
<ul>
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
</ul>
//深复制
var deepList= MyList.cloneNode(true);
alert(deepList.childNodes.length); //7
//浅复制
var shallowList= MyList.cloneNode(true);
alert(shallowList.childNodes.length); //0 

2 Document类型

Document:文档,document对象表示整个HTML页面,同时是window对象的一个属性,可以作为全局对象来访问。

Document特征:

  • nodeType:值为9;
  • nodeName:值为"#document";
  • nodeValue:值为null;
  • parentNode:值为null;
  • ownerDocument:值为null;
  • 其子节点可能是一个DocumentType(最多一个)、Element(最多一个)、processingInstruction或comment.
//1.文档的子节点:html、body、DocumentType、注释
document对象还有一个body属性,直接指向<body>元素。
eg:
//浏览器解析后,文档中包含一个子节点:<html>元素
<!--第一条注释 -->
<html>
  <body>
  </body>
</html>

//2.文档信息,可以通过documentElement或childNodes列表来访问这个元素。
//documentElement、childNodes[0]、firstChild的值相同,都指向<html>元素。
var html=document.documentElement; //取得对<html>的引用
alert(html === document.childNodes[0] ); //true
alert(html === document.firstChild); //true

var body=document.body; //取得对<body>的引用
var doctype=document.doctype; //取得对<!DOCTYPE>的引用

var originalTitle=document.title; //设置文档标题
var originalTitle=document.title; //设置文档标题
var url=document.URL; //取得完整的URL
var domain=document.domain; //取得域名
var referrer=document.referrer; //取得来源页面的URL
//3.查找元素,取得元素的操作可以使用document对象的几个方法来完成。
//getElementById()、getElementsByTagName()
//getElementById():接收一个参数:要取得的元素的ID。结果:返回该元素或null。
eg:
<div id="myDiv">Some text</div>
var div = document.getElementById("myDiv");  //取得<div>元素的引用

 3 Element类型

Element类型用于表现XML或HTML元素,提供了对元素标签名,子节点及特性的访问.

Element 节点具有以下特征:

  • nodeType 的值为 1
  • nodeName 的值为元素的标签名;
  • nodeValue 的值为 null
  • parentNode 可能是 Document Element
  • 其子节点可能是 ElementTextCommentProcessingInstructionCDATASection EntityReference.
eg://元素标签名:div,拥有一个值为mydiv的ID.
<div id="myDiv"></div>
//通过getElementById()方法取得元素及其标签名
var div = document.getElementById("myDiv");
alert(div.tagName); //"DIV",HTML中标签名始终以全部大写表示,xml中,标签名则始终会与源代码中保持一致.
alert(div.tagName == div.nodeName); //true 

3.1 HTML元素

id,元素在文档中的唯一标识符。
title,有关元素的附加说明信息,一般通过工具提示条显示出来。
lang,元素内容的语言代码,很少使用。
dir,语言的方向,值为"ltr"(left-to-right,从左至右)或"rtl"(right-to-left,从右至左),也很少使用。
className,与元素的 class 特性对应,即为元素指定的 CSS 类。

eg1:
<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>

//元素中指定的所有信息,都可以通过下列 JavaScript 代码取得
var div = document.getElementById("myDiv");
alert(div.id); //"myDiv""
alert(div.className); //"bd"
alert(div.title); //"Body text"
alert(div.lang); //"en"
alert(div.dir); //"ltr"
//当然,像下面这样通过为每个属性赋予新的值,也可以修改对应的每个特性:
div.id = "someOtherId";
div.className = "ft";
div.title = "Some other text";
div.lang = "fr";
div.dir ="rtl"; 

3.2 操作特性

取得特性,操作特性的DOM方法主要有3个:getAttribute()setAttribute()removeAttribute() .

//getAttribute()方法,取得特性,给定名称的特性不存在,getAttribute()返回null.自定义特性不存在,显示undefined.
var div = document.getElementById("myDiv");
alert(div.getAttribute("id")); //"myDiv"
alert(div.getAttribute("class")); //"bd"
alert(div.getAttribute("title")); //"Body text"
alert(div.getAttribute("lang")); //"en"
alert(div.getAttribute("dir")); //"ltr"
//setAttribute()设置特性,接收2个参数:要设置的特性名和值.
//特性存在,指定值替换现有的值;特性不存在,创建该属性并设置相应的值.
div.setAttribute("id", "someOtherId");
div.setAttribute("class", "ft");
div.setAttribute("title", "Some other text");
div.setAttribute("lang","fr");
div.setAttribute("dir", "rtl");
//所有特性都是属性,直接给属性赋值可以设置特性的值.
div.id = "someOtherId";
div.align = "left";
//removeAttribute(),用于彻底删除元素的特性.
div.removeAttribute("class");

 3.3 attributes属性

Element类型是使用attributes属性的唯一一个DOM节点类型.attributes属性中包含一个NameNodeMap,与NodeList类似,也是一个动态集合.元素的每一个特性都由一个Attr节点表示,每个节点都保存在NameNodeMap对象中.

NameNodeMap对象拥有的方法:

  • getNamedItem(name):返回 nodeName 属性等于 name 的节点;
  • removeNamedItem(name):从列表中移除 nodeName 属性等于 name 的节点;
  • setNamedItem(node):向列表中添加节点,以节点的 nodeName 属性为索引;
  • item(pos):返回位于数字 pos 位置处的节点。 

4 Text类型

 文本节点由 Text 类型表示,包含的是可以照字面解释的纯文本内容。纯文本中可以包含转义后的HTML 字符,但不能包含 HTML 代码。

Text 节点具有以下特征:

  • nodeType 的值为 3
  • nodeName 的值为"#text"
  • nodeValue 的值为节点所包含的文本;
  • parentNode 是一个 Element
  • 不支持(没有)子节点。可以通过 nodeValue 属性或 data 属性访问 Text 节点中包含的文本,这两个属性中包含的值相同。对 nodeValue 的修改也会通过 data 反映出来,反之亦然。使用下列方法可以操作节点中的文本。
  • appendData(text):将 text 添加到节点的末尾。
  • deleteData(offset, count):从 offset 指定的位置开始删除 count 个字符。
  • insertData(offset, text):在 offset 指定的位置插入 text
  • replaceData(offset, count, text):用 text 替换从 offset 指定的位置开始到 offset+count 为止处的文本。
  • splitText(offset):从 offset 指定的位置将当前文本节点分成两个文本节点。
  • substringData(offset, count):提取从 offset 指定的位置开始到 offset+count 为止处的字符串。
<!-- 没有内容,也就没有文本节点 -->
<div></div>
<!-- 有空格,因而有一个文本节点 -->
<div> </div>
<!-- 有内容,因而有一个文本节点 -->
<div>Hello World!</div>

5 Comment类型

注释在 DOM 中是通过 Comment 类型来表示的,可以通过 nodeValue data 属性来取得注释的内容。

Comment 节点具有下列特征:

  • nodeType 的值为 8
  • nodeName 的值为"#comment"
  • nodeValue 的值是注释的内容;
  • parentNode 可能是 Document Element
  • 不支持(没有)子节点。
//注释节点可以通过其父节点来访问,以下面的代码为例。
<div id="myDiv"><!--A comment --></div>
//注释节点是<div>元素的一个子节点,因此可以通过下面的代码来访问它。
var div = document.getElementById("myDiv");
var comment = div.firstChild;
alert(comment.data); //"A comment"
var comment = document.createComment("A comment "); //传递注释文本并创建注释节点

6 CDATASection类型

  CDATASection 类型只针对基于 XML 的文档,表示的是 CDATA 区域。与 Comment 类似,CDATASection 类型继承自 Text 类型,因此拥有除 splitText()之外的所有字符串操作方法。
CDATASection 节点具有下列特征:

  • nodeType 的值为 4;
  • nodeName 的值为"#cdata-section";
  • nodeValue 的值是 CDATA 区域中的内容;
  • parentNode 可能是 Document 或 Element;
  • 不支持(没有)子节点。

7 DocumentType类型

DocumentType-Type 包含着与文档的 doctype 有关的所有信息,它具有下列特征:

  • nodeType 的值为 10;
  • nodeName 的值为 doctype 的名称;
  • nodeValue 的值为 null;
  • parentNode 是 Document;
  • 不支持(没有)子节点。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
//DocumentType 的 name 属性中保存的就是"HTML":
alert(document.doctype.name); //"HTML"

8 DocumentFrament类型

  在所有节点类型中,只有 DocumentFragment 在文档中没有对应的标记。 DOM 规定文档片段(document fragment)是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。

DocumentFragment 节点具有下列特征:

  •  nodeType 的值为 11;
  •  nodeName 的值为"#document-fragment";
  •  nodeValue 的值为 null;
  •  parentNode 的值为 null;
  •  子节点可以是 Element、 ProcessingInstruction、 Comment、 Text、 CDATASection 或EntityReference。

9 Attr类型

元素的特性在 DOM 中以 Attr 类型来表示。在所有浏览器中(包括 IE8),都可以访问 Attr 类型的构造函数和原型。从技术角度讲,特性就是存在于元素的 attributes 属性中的节点。

特性节点具有下列特征:

  •  nodeType 的值为 2;
  •  nodeName 的值是特性的名称;
  •  nodeValue 的值是特性的值;
  •  parentNode 的值为 null;
  •  在 HTML 中不支持(没有)子节点;
  •  在 XML 中子节点可以是 Text 或 EntityReference。

1.2 DOM操作技术

总结:DOM是API,用于访问和操作HTML和XML文档。DOM1把HTML和XML文档看作一个层次化的节点树,可以操作这个节点树。

DOM由各种节点构成:

最基本的节点类型是Node类型,用于抽象地表示文档中一个独立的部分。其他所有类型都继承自Node。

Document类型:整个文档,是一组分层节点的根节点。document对象,可以查询和取得节点。

Element类型:Element节点表示文档中所有的HTML或XML元素,可以用来操作这些元素的内容和特性。

节点类型:文本内容类型、注释类型、文档类型、 CDATA区域类型、文档类型。

2 DOM扩展

2.1 选择符API

2.2 元素遍历

2.3 HTML5

2.4 专有扩展

3 DOM2和DOM3

3.1 DOM变化

3.2 样式

3.3 遍历

3.4 范围

4 事件

HTML与Javascript之间的交互是通过事件实现的。

事件:文档或浏览器窗口中发生的一些特定的交互瞬间。事件就是用户或浏览器自身执行的某种动作。比如:click、load、mouseover都是事件名字。事件可以通过侦听器(或处理程序)来预定事件,以便事件发生时执行相应的代码。

事件流:描述从页面中接收事件的顺序。IE的事件流叫时间冒泡流(event bubbling),Netscape Communicator的事件流是时间捕获流。

4.1 事件流

事件冒泡:事件开始时由最具体的元素接收,然后逐级传播到较为不具体的节点(文档)。

比如:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Document</title>
</head>
<body>
  <div id="myDiv">Click Me</div>
</body>
</html>

点击页面中的div元素,这个click事件会按照如下顺序传播。

事件流如图:

4.2 事件处理程序

事件处理程序[事件侦听器]:响应某个事件的函数。事件处理程序的名字都是以"on"开头。比如click事件的事件处理程序是onclick,load事件的事件处理程序是onload.

 

posted @ 2020-06-30 23:14  wendyw  阅读(251)  评论(0编辑  收藏  举报