Skip to content

一、DOM基本概念

1. DOM基本概念

  • DOM是JS操控HTML和CSS的桥梁。
  • DOM是JS操作HTML变得优雅。
  • DOM(Document Object Model,文档对象模型)是JavaScript操作HTML文档的接口,使文档操作变得非常优雅、简便。
  • DOM最大的特点就是将文档表示为节点树。

dom-tree

  • 节点的nodeType属性可以显示这个节点具体的类型。
    nodeType值节点类型
    1元素节点,例如<p><div>
    3文字节点
    8注释节点
    9document节点
    10DTD节点

二、节点访问和位置关系

1. 访问元素节点

  • 所谓"访问"元素节点,就是指"得到"、"获取"页面上的元素节点。
  • 对节点进行操作,第一步就是要得到它。
  • 访问元素节点主要依靠document对象。
  • 认识document对象

    • document对象是DOM中最重要的东西,几乎所有DOM的功能都封装在了document对象中.
    • document对象也表示整个HTML文档,它是DOM节点树的根。
    • document对象的nodeType属性值是9
  • 访问元素节点的常用方法

    方法功能兼容性
    document.getElementById()通过id得到元素IE6
    document.getElementByTagName()通过标签名得到元素数组IE6
    document.getElementByClassName()通过类名得到元素数组IE9
    document.querySelector()通过选择器得到元素IE8部分兼容 IE9完全兼容
    document.querySelectorAll()通过选择器得到元素数组IE8部分兼容 IE9完全兼容
  • document.getElementById()功能是通过id得到元素节点

    html
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script>
            // 给window对象添加onload事件监听。onload表示页面都加载完毕了。
            window.onload = function () {
                // 得到盒子1
                var box1 = document.getElementById('box1');
                // 得到盒子2
                var box2 = document.getElementById('box2');
    
                console.log(box1);
                console.log(box2);
            };
        </script>
    </head>
    
    <body>
        <div id="box1">我是盒子1</div>
        <div id="box2">我是盒子2</div>
    </body>
    
    </html>
    • 参数就是元素节点的id,注意不要写#号
    • 通常JS代码一定要写到HTML节点的后面,否则JS无法找到相应HTML节点。
    • 可以使用window.onload = function(){}事件,使页面加载完毕后,再执行指定的代码。
    • 如果页面上有相同id的元素,则只能得到第一个
    • 不管元素藏的位置有多深,都能通过id把它找到。
  • document.getElementByTagName()功能是通过标签名得到节点数组。

    html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="box1">
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
        </div>
        <div id="box2">
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
        </div>
       
        <script>
            // 先得到box1
            var box1 = document.getElementById('box1');
            // 得到box1中的p标签的数组
            var ps_inbox1 = box1.getElementsByTagName('p');
    
            console.log(ps_inbox1);
        </script>
    </body>
    </html>
    • 数组方便遍历,从而可以批量操控元素节点
    • 即使页面只有一个指定标签名的节点,也将得到长度为1的数组
    • 任何一个节点元素也可以调用getElementsByTagName()方法,从而得到其内部的某种类的元素节点。
  • document.getElementByClassName()功能是通过类名得到节点数组

    html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div class="spec">
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
        </div>
        <div class="spec">
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
        </div>
    
        <script>
            // box
            var box = document.getElementsByClassName('spec');
            console.log(box);
        </script>
    </body>
    </html>
    • 注意不要写.
    • document.getElementByClassName()方法从IE9开始兼容
    • 某个节点元素也可以调用document.getElementByClassName()方法,从而得到其他内部的某类名的元素节点。
  • querySelector()方法的功能是通过选择器得到元素

    html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="box1">
            <p class="spec">我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
        </div>
    
        <script>
            var p = document.querySelector('#box1 .spec');
            console.log(p);
        </script>
    </body>
    </html>
    • querySelector()方法只能得到页面上一个元素,如果有多个元素符合条件,则只能得到第一个元素。
    • querySelector()方法从IE8开始兼容,但从IE9开始支持CSS3的选择器,但从IE9开始支持CSS3的选择器, 如:nth-child():[src^='dog']等CSS3选择器形式都支持良好。
  • querySelectorAll()方法的功能是通过选择器得到元素数组

    • 即使页面上只有一个符合选择器的节点,也将得到长度为1的数组

2. 节点的关系

关系考虑所有节点
子节点childNodes
父节点parentNodes
第一个子节点fristChild
最后一个子节点lastChild
前一个兄弟节点previousSibling
后一个兄弟节点nextSibling

node

  • DOM中,文本节点也属于节点,在使用节点的关系时一定要注意

  • 在标准的W3C规范中,空白文本节点也应该算作节点,但是在IE8及以前的浏览器会有一定的兼容问题,它们不把空白文本节点当做节点。

  • 排除文本节点的干扰,从IE9开始支持一些"只考虑元素节点"的属性

    关系考虑所有节点只考虑元素节点
    子节点childNodeschildren
    父节点parentNodeschildren
    第一个子节点fristChildfristElementChild
    最后一个子节点lastChildlastElementChild
    前一个兄弟节点previousSiblingpreviousElementSibling
    后一个兄弟节点nextSiblingnextElementSibling
    html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="box">
            <p>我是段落A</p>
            <p id="para">我是段落B</p>
            <p>我是段落C</p>
        </div>
    
        <script>
            var box = document.getElementById('box');
            var para = document.getElementById('para');
    
            // 所有子节点
            console.log(box.childNodes);
            // 所有的元素子节点(IE9开始兼容)
            console.log(box.children);
            
            // 第一个子节点
            console.log(box.firstChild);
            console.log(box.firstChild.nodeType);
            // 第一个元素子节点(IE9开始兼容)
            console.log(box.firstElementChild);
            
            // 最后一个子节点
            console.log(box.lastChild);
            console.log(box.lastChild.nodeType);
            // 最后一个元素子节点(IE9开始兼容)
            console.log(box.lastElementChild);
    
            // 父节点
            console.log(para.parentNode);
            
            // 前一个兄弟节点
            console.log(para.previousSibling);
            // 前一个元素兄弟节点(IE9开始兼容)
            console.log(para.previousElementSibling);
            
            // 后一个兄弟节点
            console.log(para.nextSibling);
            // 后一个元素兄弟节点(IE9开始兼容)
            console.log(para.nextElementSibling);
        </script>
    </body>
    </html>
  • IE6也能兼容的"寻找所有元素子节点"函数

  • IE6也能兼容的"寻找前一个元素兄弟节点"函数

  • 获取某元素的所有兄弟节点

    html
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
        <div id="box">
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
            <p id="fpara">我是段落fpara</p>
            我是文本
            <!-- 我是注释 -->
            <p id="para">
                我是段落para
                <span>1</span>
                <span>2</span>
                <span>3</span>
            </p>
            <p>我是段落</p>
            <p>我是段落</p>
            <p>我是段落</p>
        </div>
    
        <script>
            var box = document.getElementById('box');
            var para = document.getElementById('para');
            var fpara = document.getElementById('fpara');
    
            // 封装一个函数,这个函数可以返回元素的所有子元素节点(兼容到IE6),类似children的功能
            function getChildren(node) {
                // 结果数组
                var children = [];
                // 遍历node这个节点的所有子节点,判断每一个子节点的nodeType属性是不是1
                // 如果是1,就推入结果数组
                for (var i = 0; i < node.childNodes.length; i++) {
                    if (node.childNodes[i].nodeType == 1) {
                        children.push(node.childNodes[i]);
                    }
                }
                return children;
            }
    
            console.log(getChildren(box));
            console.log(getChildren(para));
    
            // 封装一个函数,这个函数可以返回元素的前一个元素兄弟节点(兼容到IE6),类似previousElementSibling的功能
            function getElementPrevSibling(node) {
                var o = node;
                // 使用while语句
                while (o.previousSibling != null) {
                    if (o.previousSibling.nodeType == 1) {
                        // 结束循环,找到了
                        return o.previousSibling;
                    }
    
                    // 让o成为它的前一个节点,就有点“递归”的感觉
                    o = o.previousSibling;
                }
                return null;
            }
    
            console.log(getElementPrevSibling(para));
            console.log(getElementPrevSibling(fpara));
    
            // 封装第三个函数,这个函数可以返回元素的所有元素兄弟节点
            function getAllElementSibling(node) {
                // 前面的元素兄弟节点
                var prevs = [];
                // 后面的元素兄弟节点
                var nexts = [];
                
                var o = node;
                // 遍历node的前面的节点
                while(o.previousSibling != null) {
                    if(o.previousSibling.nodeType == 1){
                        prevs.unshift(o.previousSibling);
                    }
                    o = o.previousSibling;
                }
    
                o = node;
    
                // 遍历node的后面的节点
                while(o.nextSibling != null) {
                    if(o.nextSibling.nodeType == 1){
                        nexts.push(o.nextSibling);
                    }
                    o = o.nextSibling;
                }
    
                // 将两个数组进行合并,然后返回
                return prevs.concat(nexts);
            }
    
            console.log(getAllElementSibling(para));
        </script>
    </body>
    
    </html>

三、节点操作

1. 节点操作

  • 如何改变元素节点中的内容

    • 改变元素节点中的内容可以使用两个相关的属性:
      • innerHTML
      • innerText
    • innerHTML属性能以HTML语法设置节点中的内容。
    • innerText属性只能以单纯文本的形式设置节点中的内容。
      html
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
      </head>
      <body>
          <div id="box"></div>
      
          <script>
              var oBox = document.getElementById('box');
      
              oBox.innerHTML = '张三';
              oBox.innerHTML = '<ul><li>牛奶</li><li>咖啡</li></ul>';
      
          </script>
      </body>
      </html>
  • 如何改变元素节点的CSS样式

    • 改变元素节点的CSS样式需要使用这样的语句
      html
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
          <style>
              .box{
                  width: 200px;
                  height: 200px;
                  border: 1px solid #000;
              }
          </style>
      </head>
      <body>
          <div class="box" id="box">
              你好
          </div>
      
          <script>
              var oBox = document.getElementById('box');
      
              // oBox.style.backgroundColor = 'rgb(100, 200, 123)';
              // oBox.style.backgroundColor = '#f80';
      
              // oBox.style.backgroundImage = 'url(https://www.imooc.com/static/img/index/logo-recommended.png)';
              // oBox.style.backgroundSize = 'contain';
      
              oBox.style.fontSize = '50px';
          </script>
      </body>
      </html>
  • 如何改变元素节点的HTML属性

    • 标准W3C属性,如src、href等等,只需要直接打点进行更改即可

    • 不符合W3C标准的属性,要使用setAttribute()getAttribute()来设置、读取

      html
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
      </head>
      <body>
          <img src="images/1.jpg" id="pic">
          <a href="http://www.baidu.com" id="link">
              去百度
          </a>
      
          <script>
              var oPic = document.getElementById('pic');
              var oLink = document.getElementById('link');
      
              oPic.src = 'images/2.jpg';
      
              oLink.href = 'http://www.baidu.com';
              oLink.innerText = '去百度';
          </script>
      </body>
      </html>
      html
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
      </head>
      <body>
          <div id="box"></div>
      
          <script>
              var box = document.getElementById('box');
              box.setAttribute('data-n', 10);
              
              var n = box.getAttribute('data-n');
              alert(n);
          </script>
      </body>
      </html>

2. 节点创建

  • document.createElement()方法用于创建一个指定tagName的HTML元素

  • 孤儿节点

    • 新创建的节点是"孤儿节点",这意味着它并没有被挂载到DOM树上,我们无法看到它。
    • 必须继续使用appendChild()或者insertBefore()方法将孤儿节点插入到DOM树上。
  • appendChild()方法

    • 任何已经在DOM树上的节点,都可以调用appendChild()方法,它可以将孤儿节点挂载到它的内部,成为它的最后一个子节点
  • insertBefore()方法

    • 任何已经在DOM树上的节点,都可以调用insertBefore()方法,它可以将孤儿节点挂载到它的内部,成为它的"标杆子节点"之前的节点

3. 移动节点

  • 如果将已经挂载到DOM树上的节点成为appendChild()或者insertBefore()的参数,这个节点将会被移动
  • 这意味着一个节点不能同时位于DOM树的两个位置

4. 删除节点

  • removeChild()方法从DOM中删除一个子节点
  • 节点不能主动删除自己,必须由父节点删除它

5. 克隆节点

  • cloneNode()方法可以克隆节点,克隆出的节点是"孤儿节点"
  • 参数是一个布尔值,表示是否采用深度克隆:如果为true,则该节点的所有后代节点也都会被克隆,如果为false,则只克 隆该节点本身

Released under the MIT License.