zoukankan      html  css  js  c++  java
  • DOM系列---基础篇

    DOM系列---基础篇

     

    DOM (Document Object Model) 即文档对象模型, 针对 HTML 和 XML 文档的 API (应用程序接口) 。DOM 描绘了一个层次化的节点树,运行开发人员添加、移除和修改页面的某一部分。DOM 产生于 网景公司及微软公司创始的 DHTML(动态 HTML) ,但现在它已经成为表现和操作页面标记的真正跨平台、语言中立的方式。

    DOM 中的三个字母:

    D(文档)可以理解为整个 Web 加载的网页文档;

    O(对象)可以理解为类似 window 对象之类的东西,可以调用属性和方法,这里我们说的是 document对象;

    M(模型)可以理解为网页文档的树型结构。

    DOM 有三个等级,分别是 DOM1、DOM2、DOM3。

    PS:IE 中的所有 DOM 对象都是以 COM 对象的形式实现的,这意味着 IE 中的 DOM

    可能会和其他浏览器有一定的差异。

    一.DOM介绍

    1.节点

    加载 HTML 页面时, Web 浏览器生成一个树型结构, 用来表示页面内部结构。 DOM 将这种树型结构理解为由节点组成。

     

    图1

     

    从上图的树型结构,我们理解几个概念,html 标签没有父辈,没有兄弟,所以 html 标签为根标签。head 标签是 html 子标签,meta 和 title 标签之间是兄弟关系。如果把每个标签当作一个节点的话,那么这些节点组合成了一棵节点树。

    PS:后面我们经常把标签称作为元素,是一个意思。

     

    2.节点种类:元素节点,属性节点,文本节点

    例如:<div title="标签属性">测试 Div</div>

     

    图2

    二.查找元素

    W3C 提供了比较方便简单的定位节点的方法和属性, 以便我们快速的对节点进行操作。

    分别为:

     

    图3

     

    1.getElementById()方法

    getElementById()方法,接受一个参数:获取元素的 ID。如果找到相应的元素则返回该元素的 HTMLDivElement 对象,如果不存在,则返回 null。

    document.getElementById('box');          //获取 id 为 box 的元素节点

    注意:某些低版本的浏览器会无法识别 getElementById()方法,比如 IE5.0-,这时需要做一些判断,可以结合上章的浏览器检测来操作。

    if (document.getElementById) {     //判断是否支持 getElementById

    alert('当前浏览器支持 getElementById');

    }

    PS:一个程序要想写的健壮,需要很多的判断语句,方方面面考虑周到!

    当我们通过 getElementById()获取到特定元素节点时, 这个节点对象就被我们获取到了,而通过这个节点对象,我们可以访问它的一系列属性。

     

    图4

     

    例如:<div id=”box” title="标签属性">测试 Div</div>

    document.getElementById('box').tagName;           //输出:DIV

    document.getElementById('box').innerHTML;      //输出:测试 Div

    PS:innerHTML获取这个元素节点里的文本(包含HTML标签),纯文本不能包含标签,innerHTML获取的是这个元素的文本内容,而不是文本节点。

    还可以赋值:

    var box = document.getElementById('box');

    box.innerHTML = '玩转<strong>JS</strong>'; //赋值

    注意:上述赋值语句中,HTML标签会被页面解析,所以在页面显示的时候“JS”会加粗显示。

     

    图5

    例如:<div id="box" title="标题" class="pox" style="color:red;" bbb="aaa">测试Div</div>

    var box = document.getElementById('box');

    alert(box.id);                               //获取这个元素节点id属性的值,注意不是属性节点alert(box.title);                      //获取title属性的值

    alert(box.style);                          //获取style属性对象

    alert(box.style.color);               //获取style属性对象中color属性的值

    alert(box.class);                          //貌似是保留字

    alert(box.className);              //获取class属性的值

    以上都是HTML属性的直接调用,当然后面还有几种方式可以调用。

    alert(box.bbb);                            //自定义属性,直接获取,非IE不支持

    PS:如果有浏览器不支持,那么必须做兼容操作,或者尽可能不去使用。

    同样:

    也可以通过上述属性赋值:

    document.getElementById('box').style.color = 'red';    //设置 style 对象中 color 的值

    document.getElementById('box').className = 'box';   //设置 class

    2.getElementsByTagName()方法

    getElementsByTagName()方法将返回一个对象数组 HTMLCollection(NodeList),这个数组保存着所有相同元素名的节点列表。

    document.getElementsByTagName('*');       //获取所有元素

    PS:IE 浏览器在使用通配符的时候,会把文档最开始的 html 的规范声明当作第一个元素节点,所以在求length的时候,IE会比谷歌火狐多一个。代码示例:

    window.onload = function () {

             var all = document.getElementsByTagName("*");

             alert(all.length);

             alert(all[0].tagName);  //谷歌火狐返回HTML,IE返回!

    };

    HTML部分代码:

    <ul>

             <li>1</li>

    <li>2</li>

             <li>3</li>

    </ul>

    JS部分代码:

    document.getElementsByTagName('li'); //获取所有 li 元素,返回数组

    document.getElementsByTagName('li')[0]; //获取第一个 li 元素,HTMLLIElement

    document.getElementsByTagName('li').item(0) //获取第一个 li 元素,HTMLLIElement

    document.getElementsByTagName('li').length; //获取所有 li 元素的数目

    获取body节点对象:

    var body = document.getElementsByTagName('body')[0];

    alert(body);    //返回 HTMLBodyElement对象,body节点

    3.getElementsByName()方法

    getElementsByName()方法可以获取相同名称(name)的元素,返回一个对象数组HTMLCollection(NodeList)

    document.getElementsByName('add')                                       //获取 input 元素

    document.getElementsByName('add')[0].value             //获取 input 元素的 value 值

    document.getElementsByName('add')[0].checked        //获取 input 元素的 checked 值

    PS:对于并不是 HTML 合法的属性,那么在 JS 获取的兼容性上也会存在差异,IE 浏览器支持本身合法的 name 属性,而不合法的就会出现不兼容的问题,例如,name 属性本身不是div里的属性,所以IE就忽略掉。

    4.getAttribute()方法

    getAttribute()方法将获取元素中某个属性的值。 它和直接使用.属性获取属性值的方法有一定区别。

    document.getElementById('box').getAttribute('id');      //获取元素的 id 值

    document.getElementById('box').id;                                 //获取元素的 id 值

    document.getElementById('box').getAttribute('mydiv');        //获取元素的自定义属性值

    上述获取自定义属性值的方法各浏览器都支持,区别于.属性的方法,代码如下:

    document.getElementById('box').mydiv                  //获取元素的自定义属性值, 非IE不支持

    document.getElementById('box').getAttribute('class');                   //获取元素的 class 值,IE 不支持

    document.getElementById('box').getAttribute('className');        //非 IE 不支持

    //跨浏览器获取className(注:不过貌似高版本的都修复了这个问题了!!!)

    复制代码
    复制代码
    1 if (box.getAttribute('className') == null) {
    2 
    3          alert(box.getAttribute('class'));
    4 
    5 } else {
    6 
    7          alert(box.getAttribute('className'));
    8 
    9 }
    复制代码
    复制代码

    PS: HTML 通用属性 style 和 onclick, IE7 更低的版本 style 返回一个对象, onclick 返回一个函数式。虽然 IE8 已经修复这个 bug,但为了更好的兼容,开发人员只有尽可能避免使用 getAttribute()访问 HTML 属性了,或者碰到特殊的属性获取做特殊的兼容处理。

    5.setAttribute()方法

    setAttribute()方法将设置元素中某个属性和值。它需要接受两个参数:属性名和值。如果属性本身已存在,那么就会被覆盖。

    document.getElementById('box').setAttribute('align','center');    //设置属性和值

    document.getElementById('box').setAttribute('bbb','ccc');            //设置自定义的属性和值

    PS:在 IE7 及更低的版本中,使用 setAttribute()方法设置 class 和 style 属性是没有效果的,虽然 IE8 解决了这个 bug,但还是不建议使用

    6.removeAttribute()方法

    removeAttribute()可以移除 HTML 属性。

    document.getElementById('box').removeAttribute('style');           //移除属性

    PS:IE6 及更低版本不支持 removeAttribute()方法。

    三.DOM 节点

    1.node节点属性

    节点可以分为元素节点、属性节点和文本节点,而这些节点又有三个非常有用的属性,分别为:nodeName、nodeType和 nodeValue

     

    图6

     

    示例:<div id="box">测试Div<em>倾斜</em>结尾</div>

    var box = document.getElementById('box');

    //alert(box);

    //alert(box.nodeName);           //获取元素节点的标签名,tagName等价

    //alert(box.nodeType);              //获取元素节点的类型值,1

    alert(box.nodeValue);               //元素节点本身没有内容,null

    注意:node本身把节点指针放在元素<div></div>上,也就是说,本身是没有value;如果要输出<div>xxx</div>中里面包含的文本内容,那么用前面的innerHTML(innerHTML只能用于元素节点)

    alert(box.innerHTML);              //获取元素节点里面的文本内容

    PS:“测试Div<em>倾斜</em>结尾”,如果当作元素节点的文本内容(文本节点不等于文本内容),他就是一个整体。node只能获取当前节点的东西。

    2.层次节点属性

    节点的层次结构可以划分为: 父节点与子节点、 兄弟节点这两种。 当我们获取其中一个

    元素节点的时候,就可以使用层次节点属性来获取它相关层次的节点。

     

    图7

     

    1).childNodes 属性

    childeNodes 属性可以获取某一个元素节点的所有子节点,这些子节点包含元素子节点和文本子节点

    示例:<div id="box">测试Div<em>倾斜</em>结尾</div>

    var box = document.getElementById('box');           //获取一个元素节点

    alert(box.childNodes.length);                                     //3,获取这个元素节点的所有子节点

    alert(box.childNodes[0]);                                             //获取第一个子节点对象

    alert(box.childNodes[0].nodeValue);                          ////获取第一个子节点对象内容

    PS:使用 childNodes[n]返回子节点对象的时候,有可能返回的是元素子节点,比如HTMLElement;也有可能返回的是文本子节点,比如 Text。元素子节点可以使用 nodeName或者 tagName 获取标签名称,而文本子节点可以使用 nodeValue 获取。

    //示例:通过判断节点类型,来获取不同的输出

            

    复制代码
    复制代码
     1  for (var i = 0; i < box.childNodes.length; i ++) {
     2 
     3                    if (box.childNodes[i].nodeType === 1) {
     4 
     5                             alert('元素节点:' + box.childNodes[i].nodeName);
     6 
     7                    } else if (box.childNodes[i].nodeType === 3) {
     8 
     9                             alert('文本节点:' + box.childNodes[i].nodeValue);
    10 
    11                    }
    12 
    13          }
    复制代码
    复制代码

    innerHTML& nodeValue区别:

    PS:在获取到文本节点的时候,是无法使用 innerHTML 这个属性输出文本内容的。这个非标准的属性必须在获取元素节点的时候,才能输出里面包含的文本(上面提到过了)。

    PS: innerHTML 和 nodeValue 第一个区别, 就是取值的。 那么第二个区别就是赋值的时候, nodeValue 会把包含在文本里的 HTML 转义成特殊字符, 从而达到形成单纯文本的效果。

    box.childNodes[0].nodeValue = '<strong>abc</strong>';      

    //结果为:<strong>abc</strong>(纯文本,不会有加粗效果),且作用在文本节点上。

    box.innerHTML = '<strong>abc</strong>';                              

    //结果为:abc(页面中加粗显示),且作用在元素节点上。

    2).firstChild 和 lastChild 属性

    firstChild 用于获取当前元素节点的第一个子节点, 相当于 childNodes[0]; lastChild 用于获取当前元素节点的最后一个子节点,相当于 childNodes[box.childNodes.length - 1]。

    alert(box.firstChild.nodeValue);              //获取第一个子节点的文本内容

    alert(box.lastChild.nodeValue);           //获取最后一个子节点的文本内容

    3).ownerDocument 属性

    ownerDocument 属性返回该节点的文档对象根节点,返回的对象相当于 document。alert(box.ownerDocument === document); //true,根节点

    4).parentNode、previousSibling、nextSibling 属性

    parentNode 属性返回该节点的父节点;previousSibling 属性返回该节点的前一个同级节点;nextSibling 属性返回该节点的后一个同级节点

    alert(box.parentNode.nodeName);        //获取父节点的标签名

    alert(box.lastChild.previousSibling);       //获取前一个同级节点

    alert(box.firstChild.nextSibling);               //获取后一个同级节点

    5).attributes 属性

    attributes 属性返回该节点的属性节点集合。

    document.getElementById('box').attributes                    //NamedNodeMap

    document.getElementById('box').attributes.length;      //返回属性节点个数

    document.getElementById('box').attributes[0];              //Attr,返回最后一个属性节点

    document.getElementById('box').attributes[0].nodeType;             //2,节点类型

    document.getElementById('box').attributes[0].nodeValue;            //属性值

    document.getElementById('box').attributes['id'];                        //Attr,返回属性为 id 的节点

    document.getElementById('box').attributes.getNamedItem('id');              //Attr

    6).忽略空白文本节点(重点)

    var body = document.getElementsByTagName('body')[0];              //获取 body 元素节点

    alert(body.childNodes.length);                                   //得到子节点个数,IE3&&&非 IE

    PS:在非 IE 中,标准的 DOM 具有识别空白文本节点的功能;而 IE 自动忽略了,如果要保持一致的子元素节点,需要手工忽略掉它。

    法1:忽略空白文本节点

    复制代码
    复制代码
     1 function filterWhiteNode(node) {
     2 
     3                    var ret = [];
     4 
     5                    for (var i = 0; i < node.length; i ++) {
     6 
     7                             if (node[i].nodeType === 3 && /^s+$/.test(node[i].nodeValue)) {
     8 
     9                                      continue;
    10 
    11                             } else {
    12 
    13                                      ret.push(node[i]);
    14 
    15                             }
    16 
    17                    }
    18 
    19                    return ret;
    20 
    21          }
    复制代码
    复制代码

    //法2:移除空白文本节点(这个方法比较酷)

            

    复制代码
    复制代码
     1  function removeWhiteNode(node) {
     2 
     3                    for (var i = 0; i < node.length; i ++) {
     4 
     5                             if (node[i].nodeType === 3 && /^s+$/.test(node[i].nodeValue)) {
     6 
     7                       //下面第四部分会介绍移除节点方法removeChild()
     8 
     9                                      node[i].parentNode.removeChild(node[i]);
    10 
    11                             }
    12 
    13                    }
    14 
    15                    return node;
    16 
    17          }
    复制代码
    复制代码

    问题:那么如果 firstChild、lastChild、previousSibling 和 nextSibling 在获取节点的过程中遇到空白节点,我们该怎么处理掉呢?

    HTML代码部分:

    <div id="box" >

             <p>测试Div1</p>

             <p>测试Div2</p>

             <p>测试Div3</p>

    </div>

    JS代码部分:

    复制代码
    复制代码
     1 window.onload = function () {
     2 
     3          var box = document.getElementById('box');
     4 
     5          alert(removeWhiteNode(box).firstChild.nodeName);
     6 
     7 };
     8 
     9 //移除空白节点
    10 
    11 function removeWhiteNode(node) {
    12 
    13          for (var i = 0; i < node.childNodes.length; i ++) {
    14 
    15                    if (node.childNodes[i].nodeType === 3 && /^s+$/.test(node.childNodes[i].nodeValue)) {
    16 
    17                             node.childNodes[i].parentNode.removeChild(node.childNodes[i]);
    18 
    19                    }
    20 
    21          }
    22 
    23          return node;
    24 
    25 }
    复制代码
    复制代码

    四.节点操作

    DOM 不单单可以查找节点,也可以创建节点、复制节点、插入节点、删除节点和替换节点。

     

    图8

     

    1).write()方法

    write()方法可以把任意字符串插入到文档中去。

    document.write('<p>这是一个段落!</p>')';               //输出任意字符串

    2).createElement()方法

    createElement()方法可以创建一个元素节点。

    document.createElement('p');       //创建一个元素节点(仅是创建并未插入)

    3).appendChild()方法

    appendChild()方法讲一个新节点添加到某个节点的子节点列表的末尾上。

    var box = document.getElementById('box');                    //获取某一个元素节点

    var p = document.createElement('p');                               //创建一个新元素节点<p>

    box.appendChild(p);                                                                //把新元素节点<p>添加子节点末尾

    4).createTextNode()方法

    createTextNode()方法创建一个文本节点。

    var text = document.createTextNode('段落');                  //创建一个文本节点

    p.appendChild(text);                                                                //将文本节点添加到子节点末尾

    5).insertBefore()方法

    insertBefore()方法可以把节点创建到指定节点的前面。

    box.parentNode.insertBefore(p, box); //把<div>之前创建一个节点(注意要先获取到父节点)

    PS:insertBefore()方法可以给当前元素的前面创建一个节点,但却没有提供给当前元素的后面创建一个节点。那么,我们可以用已有的知识创建一个 insertAfter()函数。

    代码实现部分:

    复制代码
    复制代码
     1 function insertAfter(newElement, targetElement) {
     2 
     3 //得到父节点,就是body,但是不能直接使用body,如果层次较多,父节点不一定是body
     4 
     5          var parent = targetElement.parentNode;
     6 
     7 //如果最后一个子节点是当前元素,那么直接添加即可
     8 
     9          if (parent.lastChild === targetElement) {
    10 
    11                    alert('');
    12 
    13                    parent.appendChild(newElement, targetElement)
    14 
    15          } else {
    16 
    17 //否则,在当前节点的下一个节点之前添加
    18 
    19 //目标节点的前面添加,就可以用insertBefore;使用nextSibling获取目标节点
    20 
    21                    parent.insertBefore(newElement,targetElement.nextSibling);
    22 
    23          }
    24 
    25 }
    复制代码
    复制代码

    PS:createElement 在创建一般元素节点的时候,浏览器的兼容性都还比较好。但在几个特殊标签上,比如 iframe、input 中的 radio 和 checkbox、button 元素中,可能会在 IE6,7

    以下的浏览器存在一些不兼容。解决方法如下(注意:以下代码用到了浏览器检测文件browserdetect.js但不需要深究此文件):

    复制代码
    复制代码
     1 var body = document.getElementsByTagName('body')[0];
     2 
     3          if (BrowserDetect.browser == 'Internet Explorer' && BrowserDetect.version <= 7) {
     4 
     5                    var input = document.createElement("<input type="radio" name="sex">");
     6 
     7          } else {
     8 
     9 //标准浏览器,使用标准方式
    10 
    11                    var input = document.createElement('input');
    12 
    13                    input.setAttribute('type', 'radio');
    14 
    15                    input.setAttribute('name', 'sex');
    16 
    17          }
    18 
    19         
    20 
    21          body.appendChild(input);
    22 
    23  
    复制代码
    复制代码

    6).repalceChild()方法

    replaceChild()方法可以把节点替换成指定的节点。

    box.parentNode.replaceChild(p,box); //把<div>换成了<p>

    7).cloneNode()方法

    cloneNode()方法可以把子节点复制出来。

    var box = document.getElementById('box');

    var clone = box.firstChild.cloneNode(true); //获取第一个子节点,true 表示复制内容

    box.appendChild(clone); //添加到子节点列表末尾

    8).removeChild()方法

    removeChild()方法删除指定节点

    box.parentNode.removeChild(box); //删除指定节点

    - 转载

  • 相关阅读:
    HDU 5213 分块 容斥
    HDU 2298 三分
    HDU 5144 三分
    HDU 5145 分块 莫队
    HDU 3938 并查集
    HDU 3926 并查集 图同构简单判断 STL
    POJ 2431 优先队列
    HDU 1811 拓扑排序 并查集
    HDU 2685 GCD推导
    HDU 4496 并查集 逆向思维
  • 原文地址:https://www.cnblogs.com/wenJiaQi/p/6082703.html
Copyright © 2011-2022 走看看