JS学习9(DOM)

DOM,文档对象模型,是一个针对HTML和XML文档的一个API,它描绘了一个层次化的节点树。值得注意的是IE中的所有DOM对象都是使用COM对象实现的,这就造成了IE中的DOM对象与原生JS对象表现并不一致。

节点层次

文档节点是每个文档的根节点。在html文档中,文档节点只有一个子节点即html元素。这个元素我们称之为文档元素,每个文档只有一个文档元素,其他所有元素都包含在文档元素中。

节点分为几种不同的类型,每种类型分别表示文档中不同的信息及标记。

比如:元素节点,特性节点,文档节点,注释节点等。总共有12种节点类型,这些类型都继承自一个基类型。

Node类型

这是DOM1级定义的一个接口,DOM中所有类型节点都会实现这个接口。在JS中作为Node类型实现,所有节点类型皆继承自Node类型。不过IE直接访问不到Node。Node类型由下面12个常量表示:

  • 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)
var htmlNode = document.getElementsByTagName("html")[0];
//本来标准的写法应该是与Node.ELEMENT_NODE这个常量做比较,但是由于IE访问不到Node这个类型,所以只好直接比较
if (htmlNode.nodeType == 1){
    alert("Node is an element.");
    alert(htmlNode.nodeName);  //HTML
    alert(htmlNode.nodeValue);  //null
}

这里查找html元素时使用的方法返回的是一个NodeList对象,基本对node类型的查找和获取都会涉及到这个对象。这个对象是一个类数组对象,许多使用方法都和数组是一样的,但是它并不是Array类型的实例。其特别的地方在于它其实是基于DOM结构动态执行查询的结果,DOM结构的变化可以自动反应在NodeList中。想将NodeList转换为数组,可以使用Array.prototype.slice()方法。

var bodyNode = document.getElementsByTagName("body")[0];
var childList = bodyNode.childNodes;
var childListArray = Array.prototype.slice.call(childList,0);
alert(childList.length);  //8
alert(childListArray.length);  //8
bodyNode.removeChild(bodyNode.lastChild);
alert(childList.length);  //7
alert(childListArray.length);  //8

节点关系

就是父元素与子元素咯。

bodyNode.childNodes;
bodyNode.parentNode;
bodyNode.previousSibling;
bodyNode.nextSibling;
bodyNode.firstChild;
bodyNode.lastChild;
bodyNode.hasChildNodes();
bodyNode.ownerDocument;

不是每种节点都有子节点哦,有的不能有子节点的。

操作节点

appendChild()用于向childNodes列表结尾添加一个节点。如果传入到这个方法中的节点已经是文档的一部分了,那么该节点就会被移动到新节点。任何DOM节点不能同时出现在多个位置。

//someNode 有多个节点
var returnedNode = someNode.appendChild(someNode.firstChild);
alert(returnedNode == someNode.firstChild); //false
alert(returnedNode == someNode.lastChild); //true

insertBefore()

var returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode); //true
alert(newNode == someNode.firstChild); //true

replaceChild()

在替换的过程中,该节点的所有关系指针都会从被它替换的节点复制过来,被替换的节点还在文档中,但是失去了自己的位置。

var returnedNode = someNode.replaceChild(newNode, someNode.firstChild);

removeChild()

同样的,被移除的节点还是归文档所有,没有位置了。

var formerFirstChild = someNode.removeChild(someNode.firstChild);

cloneNode()

这个方法接受一个布尔值表示是否进行深复制,深复制就是复制节点及其子节点树。要注意的是,复制后的节点没有父节点,是孤独的节点。。需要使用上面提到的方法添加。

normalize()

这个方法是处理文档树中的文本节点。

Document类型

document是window的一个属性,是Document的实例。

  • nodeType:9
  • nodeName:”#document”
  • nodeValue:null
  • parentNode:null
  • ownerDocument:null
  • 其子节点可以是:DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction、Comment

文档的子节点

document.documentElement//指向html元素
document.body//指向body元素
document.doctype;//指向<!DOCTYPE>

文档信息

document.title = "New page title";
document.URL;
document.domain;
document.referrer;//来自哪个页面的URL

其中只有title和domain是可写的。

domain对写入的值是有限制的,只能写入当前域的父域。

//来自p2p.wrox.com
document.domain = "wrox.com";   //成功
document.domain = "nczonline.net"; //报错
document.domain = "p2p.wrox.com "; //报错

对于包含来自其他子域框架的页面这个很有用,因为来自不同域的页面不能通过JavaScript通信,所以通过将domain设置为同一个父域,就可以实现互相访问对方的JS对象。

查找元素

//这个返回一个元素
document.getElementById("myDiv");
//这个返回元素列表HTMLCollectioin
document.getElementsByTagName("img");
//找到name属性符合的元素。这个返回元素列表HTMLCollectioin
document.getElementsByName("color");
var ul = document.getElementById("myList");
//可以直接在元素里查找
var items = ul.getElementsByTagName("li");

一些特殊集合:

document.anchors
document.applets
document.forms
document.images
document.links

DOM一致性检测

用来检测浏览器实现了DOM的哪些部分。DOM1提供了一个方法。将要检测的功能和版本号传入。

var hasXmlDom = document.implementation.hasFeature("XML", "1.0");

不过这个方法并不保险,有的浏览器对没实现的功能也返回true,所以建议对不确定的直接进行能力检测。

文档写入

将输出流写入到网页中的功能。有4个方法:write()、writeln()、open()、close()。

<html>
    <head>
        <title>document.write() Example 3</title>
    </head>
    <body>
        <script type="text/javascript">
            document.write("<strong>" + (new Date()).toString() + "</strong>");
        </script>
    </body>
</html>

在文档加载过程中使用,则会加载内容到当前位置,在文档加载结束后再执行则会覆盖掉整个文档

Element类型

Element就是我们最常用的元素

- nodeType:1

- nodeName:元素的标签名

- nodeValue:null

- parentNode:Document或Element

- ownerDocument:Document

- 其子节点可以是:Element、Text、Comment、ProcessingInstruction、CDATASection、EntityReference

HTML元素

所有HTML元素都是HTMLElement或其子类。HTMLElement直接继承自Element。有这么几个通用属性:

//<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
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"

取得特性

getAttribute()、setAttribute()、removeAttribute()

alert(div.getAttribute("id"));
alert(div.getAttribute("class"));
alert(div.getAttribute("title"));
alert(div.getAttribute("lang"));
alert(div.getAttribute("data_myOwnAttr"));
alert(div.data_myOwnAttr); //undefined(除IE)

要注意的是,只有公认的特性才能通过属性名的方式来访问,自定义的特性除IE外的浏览器不会为他们创建属性。

对于style这个属性,直接访问属性得到的是一个对象,便于访问各个样式;而getAttribute(“style”)则返回字符串。

对于onclick这样的事件处理特性,直接访问属性得到的是一个函数,getAttribute()则返回字符串。

所以在访问非自定义属性时推荐使用直接访问元素属性的方法。

设置特性

div.setAttribute("id", "someOtherId");
div.id = "someOtherId";

同样,通过属性来设置自定义特性是无效的。

删除特性

div.removeAttribute("class");

attributes属性

只有Element类型有这个属性。这个属性中包含一个NameNodeMap。元素的每一个特性由一个Attr节点表示,每个节点都保存在NameNodeMap对象中。

//获取特性
var id = element.attributes.getNamedItem("id").nodeValue;
var id = element.attributes["id"].nodeValue;
//修改特性
element.attributes["id"].nodeValue = "someOtherId";
var oldAttr = element.attributes.removeNamedItem("id");
element.attributes.setNamedItem(newAttr);

创建元素

var div = document.createElement("div");
div.id = "myNewDiv";
div.className = "box";
document.body.appendChild(div);
//在IE中也可以这样
var div = document.createElement("<div id=\"myNewDiv\" class=\"box\"></div >");

遍历子节点

<ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
</ul>
<ul id="myList"><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>

对于上面的两个ul元素childNodes包含的数目可能不同,IE外的浏览器对第一个会包含3个li和4个文本节点。如果你真的要遍历,你可以在遍历的同时判断下节点的类型。

Text类型

包含纯文本内容

- nodeType:3

- nodeName:”#text”

- nodeValue:文本内容

- parentNode:Element

- ownerDocument:Document

- 无子节点

<div>Hello World!</div>
var textNode = div.firstChild;
//获取或设置文本的值
div.firstChild.nodeValue = "Some other message";
div.firstChild.data = "Some other message";

创建文本节点

var element = document.createElement("div");
element.className = "message";
//这里的大于小于号之类的会被转义,不会被解释为元素标签
var textNode = document.createTextNode("<strong>Hello</strong> world!");
element.appendChild(textNode);
//多个相邻文本节点会被拼接
var anotherTextNode = document.createTextNode("Yippee!");
element.appendChild(anotherTextNode);
document.body.appendChild(element);
//多个相邻节点导致混乱
alert(element.childNodes.length);    //2
//这个方法合并相邻文本节点
element.normalize();
alert(element.childNodes.length);    //1
alert(element.firstChild.nodeValue);

分割文本节点

被分割出来的新节点于原来的有相同的父节点。

var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);
var newNode = element.firstChild.splitText(5);

其他方法

appendData(text)

deleteData(offset, count)

insertData(offset, text)

replaceData(offset, count, text)

substringData(offset, count)

length

这些方法都是用来获取或修改文本节点中的内容的。

Comment类型

在DOM中的注释通过这个类型来表示

- nodeType:8

- nodeName:”#comment”

- nodeValue:注释文本内容

- parentNode:Document或Element

- ownerDocument:Document

- 无子节点

- 与text类型有相同的基类,所以上面的字符串方法它也有

<div id="myDiv"><!--A comment --></div>
var div = document.getElementById("myDiv");
var comment = div.firstChild;
alert(comment.data); 

CDATASection类型

DocumentType类型

DocumentFragment类型

这个类型在文档中没有对应的标记,是一个轻量级的文档,可以包含和控制节点。它不能被直接添加到文档中,但是可以作为一个仓库来使用,在里面保存将来会用到的节点。

- nodeType:11

- nodeName:”#document-fragment”

- nodeValue:null

- parentNode:null

- ownerDocument:Document

- 子节点可以是Element、ProcessingInstruction、Comment、Text、CDATASection、EntityReference

Node的各种DOM节点操作方法文档片段都继承了。

文档片段的一个使用场景就是当我们循环添加节点时,如果直接将节点添加到文档中,那么每次添加都会导致浏览器的重新渲染。如果我们先把要循环的节点添加到一个文档片段中,拼好了再添加到文档中呢,这个问题就解决了。

var fragment = document.createDocumentFragment();
var ul = document.getElementById("myList");
var li = null;
for (var i=0; i < 3; i++){
    li = document.createElement("li");
    li.appendChild(document.createTextNode("Item " + (i+1)));
    fragment.appendChild(li);
}
//当你将一个文档片段添加到文档中时,会把文档片段中的所有节点添加至文档的当前位置,而文档片段本身永远不会出现在文档中
ul.appendChild(fragment);

Attr类型

元素的特性在DOM中以Attr类型来表示。从技术角度讲,特性就是存在于元素的attributes中的节点。尽管它们是节点,但不认为它们是DOM文档树的一部分。

var ul = document.getElementById("myList");
//特性节点不会出现在文档树中
alert(ul.childNodes.length);
alert(ul.attributes["class"].value);
//alert(ul.attributes["align"].value);会报错
//添加特性节点
var attr = document.createAttribute("align");
attr.value = "left";
ul.setAttributeNode(attr);
alert(ul.attributes["align"].value);

一般只使用之前提到的getAttribute()、setAttribute()、remveAttribute()方法,很少直接引用特性节点。

DOM操作技术

动态脚本

指的是页面加载时并不存在,但将来的某一时刻通过修改DOM动态添加的脚本。动态添加同样有两种方式,添加外部文件和行内代码。

外部文件:

function loadScript(url){
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = url;
    document.body.appendChild(script);
}
loadScript("client.js");

脚本加载完成就可以使用了,但是这里我们并不能判断是否加载完成了,需要借助一些事件来判断。

行内代码:

function loadScriptString(code){
    var script = document.createElement("script");
    script.type = "text/javascript";
    try {
    //由于IE将script视作一个特殊的元素,不允许DOM访问其子节点,这样在IE中会报错
        script.appendChild(document.createTextNode(code));
    } catch (ex){
    //直接设置text属性有的浏览器不支持,但IE肯定支持
        script.text = code;
    }
    document.body.appendChild(script);
}
loadScriptString("function sayHi(){alert(‘hi‘);}");

动态样式

外部文件:

function loadStyles(url){
    var link = document.createElement("link");
    link.rel = "stylesheet";
    link.type = "text/css";
    link.href = url;
    var head = document.getElementsByTagName("head")[0];
    head.appendChild(link);
}
loadStyles("styles.css");

内联样式:

IE同样有BUG

function loadStyleString(css){
    var style = document.createElement("style");
    style.type = "text/css";
try{
    style.appendChild(document.createTextNode(css));
    } catch (ex){
        style.styleSheet.cssText = css;
    }
    var head = document.getElementsByTagName("head")[0];
    head.appendChild(style);
}
loadStyleString("body{background-color:red}");

操作表格

DOM为表格添加了一些属性和方法,以便我们可以更好的操作表格。

table元素的:

caption

tBodies

tFoot

tHead

rows

createTHead()

createTFoot()

createCaption()

deleteTFoot()

deleteCaption()

deleteRow(pos)

insertRow(pos)

body元素的:

rows

deleteRow(pos)

insertRow(pos)

cells

deleteCell(pos)

insertCell(pos)

使用NodeList

NodeList以及其近亲NamedNodeMap和HTMLCollection都是动态的,也就是说每当文档发生变化时,对他们的查询始终返回最新的信息。这也就导致了一些问题,

var divs = document.getElementsByTagName("div"),
    i,
    div;
for (i=0; i < divs.length; i++){
    div = document.createElement("div");
    document.body.appendChild(div);
}

在这段代码中每次增加一个div节点,divs中的元素也会同时增加一个,divs.length永远会比当前的循环大。

// 这样就不会有问题了
var divs = document.getElementsByTagName("div"),
    i,
    len,
    div;
var divtemp = divs;
for (i=0, len=divs.length; i < len; i++){
    div = document.createElement("div");
    document.body.appendChild(div);
}

这也提醒了我们,使用nodeList要谨慎,因为每次使用都会引起一次查询。

时间: 2024-08-07 03:34:17

JS学习9(DOM)的相关文章

js学习12-《JS DOM 编程艺术》笔记

学习了下<JS DOM 编程艺术>,做个学习总结:1.字符串中放单引号双引号:建议:字符串中放单引号,则用双引号包含字符串 1 var s1="It's my doy"; 字符串中放双引号,则用单引号包含字符串 1 var s2='He said "hi!" '; 其他使用\进行转义 2.==和====== :严格比较.不仅比较值,还比较类型== :不严格比较,转换类型一致比较 3.JS语言里对象的三种类型3.1内建对象:javascript提供的对象

JS学习之DOM节点的关系属性封装、克隆节点、Dom中Style常用的一些属性等小结

JS DOM节点: 在JS DOM中节点的关系被定义为节点的属性: 通常有以下几种节点之间的关系: (这里的关系是所有浏览器都支持的) parentNode    父节点 childNodes    子节点 firstChild    父节点里的第一个子节点 lastChild     父节点里的最后一个子节点 nextSibling    与子节点并列的下一个兄弟节点 previousSibling   与子节点并列的上一个兄弟节点 火狐与谷歌支持而ie8不支持的节点关系有: previous

js学习总结----DOM中的节点和关系属性

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="div1"> <h1>培训课程</h1> <ul> <li>html+css&

【转】Backbone.js学习笔记(二)细说MVC

文章转自: http://segmentfault.com/a/1190000002666658 对于初学backbone.js的同学可以先参考我这篇文章:Backbone.js学习笔记(一) Backbone源码结构 1: (function() { 2: Backbone.Events // 自定义事件 3: Backbone.Model // 模型构造函数和原型扩展 4: Backbone.Collection // 集合构造函数和原型扩展 5: Backbone.Router // 路由

Ext JS学习第五天 Ext_window组件(二)

此文用来记录学习笔记 •上一讲我们已经学过了window的使用,那么在这将中,我们将结合然后把Ext中需要注意的地方,以及组建的使用给予介绍.indow做几个Web开发的经典示例. •ExtWeb实战300例: –例1:点击按钮打开一个window,window重复创建的问题 •重点分析:这个问题是初学者经常会犯错的地方,一般来说简单的代码不会产生此问题,但是如果以后代码复杂以后,这个问题如果发生调试起来会非常麻烦!! 附上栗子代码 1 Ext.onReady(function () { 2 3

Angular JS 学习笔记

特定领域语言 编译器:遍历DOM来查找和它相关的属性, 分为编译和链接两个阶段, 指令:当关联的HTML结构进入编译阶段时应该执行的操作,可以写在名称里,属性里,css类名里:本质上是函数 稳定的DOM:绑定了数据模型的DOM元素的实例不会在绑定的生命周期发生改变 作用域:用来检测模型的改变和为表达式提供执行上下文的 AngularJS 和其它模板系统不同,它使用的是DOM而不是字符串 指令: 由某个属性.元素名称.css类名出现而导致的行为,或者说是DOM的变化 Filter过滤器:扮演着数据

Angular JS学习笔记

之前的学习方法有点盲目,建议以后只看与工作有关的内容,并且多问那些是只和工作有关联的. 遇到问题的时候,项目不急的话,自己研究,项目急的话,马上问. 方法不对,再努力也没有用. Angular JS学习网站:http://www.zouyesheng.com/angular.html#toc7 [  项目有关的内容 ] ng-model ng-click ng-options ng-repeat ng-if ng-show ng-hide ng-controller ng-href(有印象) {

js模块化开发——require.js学习总结

1.为什么使用require.js 作为命名空间: 作为命名空间使用: 异步加载js,避免阻塞,提高性能: js通过require加载,不必写很多script 2.require.js的加载 require.js下载 下载后,放在指定目录就可以加载了 ? 1 <script src="js/require.js"></script> 有人可能会想到,加载这个文件,也可能造成网页失去响应.解决办法有两个,一个是把它放在网页底部加载,另一个是写成下面这样: ? 1

【Knockout.js 学习体验之旅】(3)模板绑定

本文是[Knockout.js 学习体验之旅]系列文章的第3篇,所有demo均基于目前knockout.js的最新版本(3.4.0).小茄才识有限,文中若有不当之处,还望大家指出. 目录: [Knockout.js 学习体验之旅](1)ko初体验 [Knockout.js 学习体验之旅](2)花式捆绑 [Knockout.js 学习体验之旅](3)模板绑定 模板引擎 页面是由数据和HTML组件构成的,如何将数据嵌入到HTML组件里面呢?一个比较好的选择是使用模板技术. 回顾下第一篇([Knock

JS学习中....

这一周,算是最痛苦的一周了,Js的学习,Dom的理解,Js语言由于是若性语言,所以常遇到写错单词从而导致代码运行不出结果的情况,这就意味着我们写代码的时候得分外小心,分外细心了,下面这是一个简单的留言板. 标题: 姓名: 内容: body{ background-color: black; margin: 0px; padding: 0px; font-family: "微软雅黑"; color: #8f8f8f; } #div1{ width: 700px; height: 400p