DOM简介( Document Object Model 文档对象模型)

W3C

W3C 文档对象模型 (DOM) 是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。
W3C DOM 标准被分为 3 个不同的部分:

  • 核心 DOM - 针对任何结构化文档的标准模型

  • XML DOM - 针对 XML 文档的标准模型

  • HTML DOM - 针对 HTML 文档的标准模型

也就是说,DOM包含三个版本(?),对应不同的DOM模型,由于我对XML还不是很了解,这里主要先讨论HTML DOM

关于XML DOM 的W3C文档:XML DOM 教程

MDN:DOM概述

XML与HTML的区别

XML DOM解析 基础概念


什么是 HTML DOM

引自W3C:

  • HTML的标准对象模型

  • HTML 的标准编程接口

  • W3C 标准

  • HTML DOM 定义了所有 HTML 元素的对象和属性,以及访问它们的方法。
    换言之,HTML DOM 是关于如何获取、修改、添加或删除 HTML 元素的标准

引自MDN:

文档对象模型 (DOM) 是HTMLXML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来。

一个web页面是一个文档。这个文档可以在浏览器窗口或作为HTML源码显示出来。但上述两个情况中都是同一份文档。文档对象模型(DOM)提供了对同一份文档的另一种表现,存储和操作的方式。 DOM是web页面的完全的面向对象表述,它能够使用如 JavaScript等脚本语言进行修改。

我们之所以能够对Web页面进行添加、删除、更新、操控元素等等活动,就是因为这个DOM才得以实现。它定义了一套对象(方法)规则,使得JavaScript可以根据这些规则来进行编程。更像是一个文档API


DOM 节点(Node

根据 W3C 的 HTML DOM 标准,HTML 文档中的所有内容都是节点:

  • 整个文档是一个文档节点

  • 每个HTML元素是元素节点

  • HTML元素内的文本是文本节点

  • 每个HTML属性是属性节点

  • 注释是注释节点

节点树

HTML DOM 将 HTML 文档视作树结构。这种结构被称为节点树:
图片描述
图片描述
图片描述

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>     
    <body>
        <h1>Temperature Conversion</h1>
        <p>
            <input type="text" id="temperature" />
            <input type="button" id="f_to_c" value="F to C" />
            <input type="button" id="c_to_f" value="C to F" />
        </p>
        <!-- Computation result will go here-->
        <p id="result"></p>
        <script src="temperature.js"></script>
    </body>
</html>

这也被称为W3C DOM 1级核心

W3C的DOM Level 1 Core是用于更改文档内容树的强大对象模型。所有主流浏览器都支持Mozilla Firefox和Microsoft Internet Explorer。它是网络上脚本编写的强大基础。

怎么称呼这些元素?

例:

<html>
  <head>
    <title>DOM 教程</title>
  </head>
  <body>
    <h1>DOM 第一课</h1>
    <p>Hello world!</p>
  </body>
</html>
  • <html> 节点没有父节点;它是根节点

  • <head><body> 的父节点是 <html> 节点

  • 文本节点 "Hello world!" 的父节点是 <p> 节点

  • <html> 节点拥有两个子节点:<head><body>

  • <head> 节点拥有一个子节点:<title> 节点

  • <title> 节点也拥有一个子节点:文本节点 "DOM 教程"

  • <h1><p> 节点是同胞节点,同时也是 <body> 的子节点

并且

  • <head> 元素是 <html> 元素的首个子节点

  • <body> 元素是 <html> 元素的最后一个子节点

  • <h1> 元素是 <body> 元素的首个子节点

  • <p> 元素是 <body> 元素的最后一个子节点

DOM 处理中的常见错误是希望元素节点包含文本。

在本例中:<title>DOM 教程</title>,元素节点 <title>,包含值为 "DOM 教程" 的文本节点


HTML DOM

首先记住这个:

HTML DOM (文档对象模型)中,每个部分都是节点:

  • 文档本身是文档节点

  • 所有HTML元素是元素节点

  • 所有 HTML 属性是属性节点

  • HTML元素内的文本是文本节点

  • 注释是注释节点


DOM Document

每个载入浏览器的 HTML 文档都会成为 Document 对象。

Document对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。

提示:Document 对象是 Window 对象的一部分,可通过 window.document 属性对其进行访问。

document.URL

  • URL 属性可返回当前文档的 URL。
    比如在现在的窗口下,控制台输入:

alert(document.URL)

图片描述


document.getElementById()

这个大家都很熟悉了,getElementById() 方法可返回对拥有指定 ID 的第一个对象的引用。

W3C还定义了一个工具函数:getElementById() 是一个重要的方法,在 DOM 程序设计中,它的使用非常常见。我们为您定义了一个工具函数,这样您就可以通过一个较短的名字来使用 getElementById() 方法了:

  function id(x) {
      if (typeof x == "string") return document.getElementById(x);
      return x;
  }
  // 上面这个函数接受元素 ID 作为它们的参数。使用前编写 x = id(x) 就可以了。

document.getElementsByName()

getElementsByName() 方法可返回带有指定名称的对象的集合

该方法与 getElementById() 方法相似,但是它查询元素的 name 属性,而不是 id 属性。
另外,因为一个文档中的 name 属性可能不唯一(如 HTML 表单中的单选按钮通常具有相同的 name 属性),所有 getElementsByName() 方法返回的是元素的数组,而不是一个元素。

由于这个方法返回的是一个数组,不是具体的元素,所以必须注意这点:

    <input type="text" value="" name="myinput"/>
    <input type="button" value="" name="myinput" id="ID"/>
    
    <script type="text/javascript">
        var inputA = document.getElementsByName("myinput")[0]; // [0]表示获得的所有input元素中第一个
        var inputB = document.getElementById("ID");            // ID取值则很精确,因为ID的特殊性
        
        var iA = inputA.attributes;             // 元素自带对象,内含该元素所有属性(以键值对存在)
        alert(iA.length);                       // 3
        alert(iA[0].name+" : "+iA[0].value);    // "type : text"
        
        var iB = inputB.attributes;
        alert(iB.length);                       // 4
        alert(iB[0].name+" : "+iB[0].value);    // "type : button"
    </script>

document.getElementsByTagName()

注意要和上面的区分,TagName指的是标签名

getElementsByTagName() 方法可返回带有指定标签名的对象的集合,返回元素的顺序是它们在文档中的顺序。

如果把特殊字符串 "*" 传递给 getElementsByTagName() 方法,它将返回文档中所有元素的列表,元素排列的顺序就是它们在文档中的顺序。

注释:传递给 getElementsByTagName() 方法的字符串可以不区分大小写。

    <input type="text" />
    <input type="text" />
    <input type="text" />
    <script type="text/javascript">
        var x = document.getElementsByTagName("INPUT")[0];
        alert(x.tagName)            // "INPUT"
    </script>

document.write()

write() 方法可向文档写入 HTML 表达式或 JavaScript 代码。
可列出多个参数(exp1,exp2,exp3,...) ,它们将按顺序被追加到文档中。

document.write("Hello World!");

关于Document的更多属性方法可查W3C:HTML DOM Document 对象


DOM Element

简介:

  • 在 HTML DOM 中,Element 对象表示 HTML 元素(所有 HTML 元素是元素节点)。

  • Element 对象可以拥有类型为元素节点、文本节点、注释节点的子节点。

  • NodeList 对象表示节点列表,比如 HTML 元素的子节点集合。

  • 元素也可以拥有属性。属性是属性节点(参见DOM Attribute)。


element.parentNode

parentNode 属性以 Node 对象的形式返回指定节点的父节点。
如果指定节点没有父节点,则返回 null

    <div>
        <h1>H1</h1>
    </div>
    <script type="text/javascript">
        var h = document.getElementsByTagName("H1")[0];
        alert(h.parentNode.nodeName);                // "DIV"
    </script>

element.style

HTMLElement.style 属性返回一个 CSSStyleDeclaration 对象,表示元素的 内联style 属性(attribute),但忽略任何样式表应用的属性。 通过 style 可以访问的 CSS 属性列表,可以查看 CSS Properties Reference。

    <div>
        <h1>H1</h1>
    </div>
    <script type="text/javascript">
        var h = document.getElementsByTagName("H1")[0];
        h.setAttribute("style","font-size:100px;color: blue;")
    </script>

图片描述

elt.style.cssText = "color: blue"; 设置多个样式属性

elt.setAttribute("style", "color: blue"); 设置多个样式属性

elt.style.color = "blue"; 直接设置样式属性

var st = elt.style; st.color = "blue"; 间接设置样式属性

通常,要了解元素样式的信息,仅仅使用 style 属性是不够的,这是因为它只包含了在元素内嵌 style 属性(attribute)上声明的的 CSS 属性,而不包括来自其他地方声明的样式,如 <head> 部分的内嵌样式表,或外部样式表。要获取一个元素的所有 CSS 属性,你应该使用 window.getComputedStyle()。


element.childNodes;

childNodes 属性返回节点的子节点集合,以 NodeList 对象。

提示:您可以使用 length 属性来确定子节点的数量,然后您就能够遍历所有的子节点并提取您需要的信息。

Node.childNodes 返回包含指定节点的子节点的集合,该集合为即时更新的集合(live collection)。

  • 获得的Nodelist是实时更新的,如果你新增一个子节点,下次调用chilNodes属性返回的Nodelist会变化(更新)。

  • Nodelist不是数组!这一点很重要


<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>     
    <body>
        <div>this is div
            <h1 id="h1">this is H1</h1>
            <h2>this is H2</h2>
        </div>
        
        <div id="div2">这是DIV2的文本节点<p>Element P</p></div>
        <hr />
        <script type="text/javascript">
            var div = document.getElementsByTagName("div")[0];
            var child_nodes = div.childNodes;
            var h1 = document.getElementsByTagName("h1")[0];
            var h2 = document.getElementsByTagName("h2")[0];
            
// 为了看Nodelist里有什么东西,for循环出来一堆看不懂的东西:)        
            for (var i=0;i<child_nodes.length;i++) {            // 遍历这个Nodelist,并写入document文档中
                    document.write(child_nodes[i]+"<br />")
            }
            document.write("<br />");
// Nodelist有length属性,这里值为5,并且它可以删除掉
            console.log(child_nodes.length);                    // 5
            delete child_nodes.length;             
            console.log(child_nodes.length);                    // "undefined"
/**Nodelist里元素(节点)对象排序按照HTML源码的顺序排下来,第一个文本节点从div标签后开始,到H1标签前,在Nodelist里表示就是[0]
 * 第二个是H1元素节点,但是H1标签后有换行空余,这里构成了H1标签后面的文本节,即Nodelist[2]
 * 同理,H2标签后因为换行符,到DIV结束标签前产生的空余内容构成了Nostlist[4]
 */
            console.log(child_nodes[0].nodeType);                // nodeType:3,表示文本
            console.log(child_nodes[1]===h1)                    // true
            child_nodes[1].style.background = "orange";            // 返回的Nodelist因为包括子节点,可以设置样式
// div的Nodelist里[2][11]的文本节点是什么?    result:是因为H1,H2元素节点换行产生的空余,这里因为可以填充文本所以也算是文本节点
            
            console.log(h1.childNodes.length);        // 1
// H1元素的Nodelist里只有文本节点,哪怕没有像<p></p>里添加任何东西,还是存在这个文本节点

// 再使用一个全新的div来试验,div2我们不让它产生空隙
            var div2 = document.getElementById("div2").childNodes;
            for (var j=0;j<div2.length;j++) {
                document.write(j+1+"个"+div2[j]+"<br />")
            }
/*我们可以看到,这样就只有两个Node,第一个是DIV文本,第二个是P元素节点,
 * 从<div>到</div>结束,之间所有的内容都是div的子节点,包括未处理文本,但是这一特性在不同浏览器上也不一样
 * 第一个DIV,如果用IE解释,它的Nodelist只有三个节点,其他浏览器就有5个子节点*/
        </script>
    </body>
</html>

MDN:Node.childNodesNodeList

深入理解 NodeList - 挨踢前端 - 博客园

由于这个特性,所以一般推荐使用.childrenjQuery 遍历 - children() 方法


DOM Attribute

Attr 对象

  • 在 HTML DOM 中,Attr 对象表示 HTML 属性

  • HTML 属性始终属于 HTML 元素。


NamedNodeMap 对象

  • 在 HTML DOM 中,NamedNodeMap 对象表示元素属性节点的无序集合

  • NamedNodeMap 中的节点可通过名称或索引(数字)来访问


            <input type="text"  id="ID" value="VALUE" class="CLASS"/>
            <br />
            <hr />
            <script type="text/javascript">
                var Input = document.getElementsByTagName("input")[0];
//                console.log(Input.attributes)        //  "[object NamedNodeMap]"

                for (var b in Input) {                // 查看input元素节点里的属性方法
                    document.write(b+"<br />")
                }
                document.write("<hr />")            
                for (var j in Input.attributes) {    // input.attributes,即NameNodeMap对象
                    document.write(j+"<br />")
                }
                document.write("<hr />")            
                for (var x in Input.attributes[0]) {    // input元素节点里的属性节点,每个HTML标准属性都是一个属性节点
                    document.write(x+"<br />")
                }

for-in出来的东西太多就不贴图了


DOM元素含有的这两个东西,虽然完全不是一回事,但却又紧密联系在一体,不细细体会,还真不好分清。Property-属性Attribute-特性,每一个dom元素都有一个attributes属性来存放所有的attribute节点,通过getAttribute()setAttribute()方法来进行获取和操作。

Property就是一个属性,如果把DOM元素看成是一个普通的object对象,那么property就是以name=value形式存放在Object中的属性操作很简单

element.gameid = 880; // 添加
console.log( elem.gameid ) // 获取

这两个东西有什么联系和区别呢?
首先,很多attribute节点有一个相应的property属性,如例子中的input元素的idtype既是attribute也有property,不管哪种方式都可以访问和修改,但是对于自定义的attribute节点,或者自定义property,两者就没有关系了,对于IE6-7来说,没有区分attributeproperty。具体的讲解可以考attributeproperty的区别,很详细。

这段话也是我在百度知道上找的,目前我的理解也很不全面,先摆着以后慢慢看。先知道怎么使用这些属性节点和NameNodeMap对象。后续要弄懂分清除PropertyAttrubute两个对象

引用几个颇有见地的文章吧:

attribute

input节点有很多属性(attribute):‘type’,'id','value','class'以及自定义属性,在DOM中有setAttribute()和getAttribute()读写DOM树节点的属性(attribute)

PS:在这里的getAttribute方法有一个潜规则,部分属性(input的value和checked)通过getAttribut取到的是初始值

Property

javascript获取到的DOM节点对象,比如a 你可以将他看作为一个基本的js对象,这个对象包括很多属性(property),比如“value”,“className”以及一些方法,setAttribute,getAttribute,onclick等,

所有在日常的工作中,推荐是使用 property,这样事情处理起来比较简单一些,attribute永远是字符串。

来看几个常用属性/方法


  • 获取、设置、删除属性节点常用方法:

  • elementNode.attributes(属性返回包含被选节点属性的 NamedNodeMap

  • elementNode.getAttribute(name)(方法通过名称获取属性的值)

  • elementNode.setAttribute(name, value)(方法创建或改变某个新属性)

  • elementNode.removeAttribute(name)(方法通过名称删除属性的值)


attributes.value

设置或返回属性的值

        <input id="input" value="value"/>
        <script type="text/javascript">
            var i = document.getElementById("input");
            console.log(i.attributes.value.value)
        </script>

这段代码首先获得inputHTML元素,然后调用attributes返回NameNodeMap属性节点集合,里面的属性以键值对方式存在,之后调用value属性的属性值。


attribute.setNamedItem()

setNamedItem() 方法向 nodeMap 添加指定的节点。
如果此节点已存在,则将替换该节点,并返回被替换的节点,否则返回值是 null

            var i = document.getElementById("input");
            var c = document.createAttribute("class");
            c.nodeValue = "cla";
            i.attributes.setNamedItem(c)
  • 创建属性节点,设置节点值,添加到元素节点下,然后设置属性节点,这里用的是attributes方法,即namednodemap.removeNamedItem(nodename)

  • 添加属性节点也可以使用element.setAttributeNode(attributenode)方法;


关于更多:HTML DOM Attribute 对象,其中提到了不要在属性节点上使用节点对象的属性和方法

常用方法:HTML DOM


关于事件一章我会另开一篇博文继续研究


Queen
139 声望20 粉丝