[duyi]171222 DOM

本文深入解析了DOM(文档对象模型)的基本概念与应用,包括DOM作为规范的理解、文档节点的编程接口,以及如何通过JS操作HTML标签等内容。文章还详细介绍了DOM的节点类型、属性操作、内容获取与设置的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DOM 标签 -> 对象


  • API (Application Programming Interface)应用程序编程接口 :是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力。

  • DOM(Document Object Model)文档对象模型 :是表示和操作HTML和XML文档内容的 基础API(权威指南)。

  • W3C 文档对象模型 (DOM) 是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式(W3C)。

  • DOM代表着加载到浏览器窗口的当前网页。(也许DOM像一张小地图通过JS去读地图)(DOM编程艺术)。

  • HTML DOM 定义了访问和操作 HTML 文档的标准方法,提供了一套通过JS操作HTML标签的解决方案。

这里写图片描述


DOM到底是对象模型还是编程接口

  • 总的来说,DOM应该理解为是1个规范。
    站在实现(如浏览器)和使用者(如程序员)的角度来看,DOM就是一套文档节点的编程接口,只要实现了接口,就可以使用接口成员来操作文档;站在设计和制定的角度来看,DOM是一个对象模型,它将文档内容建模为对象并组织为树状结构,定义了这些对象的行为和属性以及这些对象之间的关系。

DOM如何描述文档(文档逻辑结构)


  • DOM 将 HTML 文档表达为树结构
    这里写图片描述
    《引用》 整个是一个网页,这里称之为Page。每个Page都有一个主框(Main Frame),该框通常包含一个HTML Document,主框也可能包含子框(sub frame),这些框构成一个树型结构,以主框为根节点,每个框也可能包含自己的HTML Document,它是一颗DOM树。
    http://blog.youkuaiyun.com/milado_nju/article/details/7886253

    这里写图片描述


<html>
<head>
    <title>Document</title>
</head>
<body>
    <h1>An HTML Document</h1>
    <p>This is a <li>simple</li> document.</p>
</body>
</html>

这里写图片描述


节点Node


在现实世界里,一切事物都由原子组成。原子是现实世界的节点。原子又可以分解成亚原子。
DOM将文档表达为节点树,节点树由节点组成。此时的节点是文档树的树枝和树叶。

这里写图片描述

  • 元素节点 Element Node
  • 文本节点 Text Node

    (回车与空格也是文本节点)

这里写图片描述

  • 属性节点 Attribute Node
<div><img src="./demo2.jpg"><ul title="ha"><li>demo</li></ul></div>

文档操作

document是一个浏览器提供的DOM对象,也是一个文档标签。对象中有很多方法。一个文档就是一颗节点树,一个节点就是一个对象。


1.选取元素节点(将HTML 标签 通过DOM在JS中映射成 对象

  • document.getElementById(id)
//用typeof来验证操作数的类型
alert(typeof document.getElementById('demo'));
//返回一个对象
  • document.getElementsByTagName(tag)
var a = document.getElementsByTagName("p")[0];
//其中的元素按照文档中的顺序排序,所以可以使用索引

console.log(document.getElementsByTagName('div'));
        console.log(document.getElementsByTagName('div').length);
//返回类数组对象,可以使用length属性
---------------------------------------------------------        
var a = document.getElementsByTagName('div');
for (i = 0; i < a.length; i++) {
      console.log(typeof a[i]);
//验证返回的数组中都是对象。使用键盘反复敲入代码很麻烦,将复杂的代码赋值给一个变量。
---------------------------------------------------------
<div>
      <ul id="demo">
           <p title="look">look</p>
           <p>book</p>
           <li class="po">
               <span>
                root
               </span>
           </li>
      </ul>
</div>

var b = document.getElementById('demo');
var c = b.getElementsByTagName('*');
console.log(b.nextSibling);
console.log(b.previousSibling);
console.log(b.childNodes);
console.log(c.length);
for (var i = 0; i < c.length; i++) {
    console.log(typeof c[i]);
}
//两种选择器一起使用

这里写图片描述
这里写图片描述

  • (HTMLCollection是元素集合而NodeList是节点集合(即可以包含元素,也可以包含文本节点)。所以 node.childNodes 返回 NodeList,而 node.children 和 node.getElementsByXXX 返回 HTMLCollection 。唯一要注意的是 querySelectorAll 返回的虽然是 NodeList ,但是实际上是元素集合,并且是静态的(其他接口返回的HTMLCollection和NodeList都是live的)。)

  • document.getElementsByClassName(class)
    • 即使在元素的class属性中,类名顺序是’sale important’,而非参数中写的’important sale’,也照样匹配。不仅顺序不重要,就算 元素带有更多类名也没有关系。
    • 该方法比较新,需要增强兼容性
//编写兼容性的类名获取方法
function getElementsByClassName(node, classname) {
    if (node.getElementsByClassName) {
        return node.getElementsByClassName(classname);
    } else {
        var results = new Array();
        var elems = node.getElementsByTagName('*');
        for (var i = 0; i < elems.length; i++) {
            if (elems[i].className.indexOf(classname) != -1) {
                //元素节点对象中的类名属性调用数组indexof方法 判断每次遍历的节点的类名是否与变量(传入参数)相同,即!=1
                results[results.length] = elems[i];
            }
        }
        return results;
    }
}
var po = document.getElementsByClassName('po');
console.log(po);
  • document.getElementsByName()

    • HTML的name属性最初打算为表单元素分配名字,类似class
    • 它被定义在HTMLDocument类中,对表单、表单元素、iframe、img元素有效。

—– 通过点击改变颜色

var oDiv = document.getElementsByTagName('div')[0];
        var flag = true;
        oDiv.onclick = function(){
            if(flag){
                oDiv.style.background ='orange';
            }else{
                oDiv.style.background = 'red';
            }
            flag = !flag;
}
  • 通过CSS选择器选取元素

    document.querySelectAll()
    document.querySelector()
    静态的快照,不能实时更新

document.querySelectorAll('div ul .demo .a');

2.遍历节点树

  • Node.nodeType 节点类型 ( 返回类型序号 )
  • Node.nodeValue (text节点或comment节点的文本内容)
  • Node.nodeName (元素的标签名,用大写形式表示)
  • Node.parentNode 父节点(返回父节点)
  • Node.childNodes 子节点们 (返回类数组全部子节点)
  • Node.firstChild 第一个子节点
  • Node.lastChild 最后一个子节点
  • Node.nextSibling 下一个子节点
  • Node.previousSibling 上一个节点

使用Node属性,得到文档下第一个子节点下面的第二个子节点的引用

document.childNodes[0].childNodes[1];
document.firstChild.firstChild.nextSibling;
 <ul>
     <li>1</li>
     <!-- 注释节点 -->
     <li>4</li>
     <!-- 注释节点 -->
     <li>5</li>
 </ul>
 <script>
     var oLiArray = document.getElementsByTagName('li');

     var oNewLi = document.createElement('li');

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

     oUl.appendChild(oNewLi);

     console.log(oUl.parentNode);
     console.log(oUl.childNodes);
     console.log(oUl.firstChild);
     console.log(oUl.lastChild);
     console.log(oUl.nextSibling.nextSibling);
     console.log(oUl.previousSibling);
 </script>

这里写图片描述


3.遍历元素节点树 (Element对象树:忽略文本和注释)

  • parentElement
  • firstElementChild
  • lastElementChild
  • nextElementSibling
  • previousElementSibling
  • childElementCount 子元素的数量
    <ul>
        <li>1</li>
        <!-- 注释节点 -->
        <li>4</li>
        <!-- 注释节点 -->
        <li>5</li>
    </ul>
    <script>
        var oLiArray = document.getElementsByTagName('li');

        var oNewLi = document.createElement('li');

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

        oUl.appendChild(oNewLi);

        console.log(oUl.parentElement);
        console.log(oUl.firstElementChild.nextElementSibling);

这里写图片描述


4.获取和设置属性

  • element.getAttribute(attribute) 返回字符串

  • element.setAttribute(‘attrubute’,’value’)

    • 它不属于document对象,只能通过元素节点对象调用
    • 通过setAttribute对文档做出修改后,在通过 浏览器查看源代码时,仍然是修改前的属性值,也就是说,setAttribute做出的修改不会反映在文档本身的源代码里。这种现象源自DOM的工作模式:先加载文档静态内容,在动态刷新,动态刷新不影响文档的静态内容。对页面内容进行刷新却不需要在浏览器里刷新页面。
  • element.hasAttribute(attribute) 检测属性是否存在
  • element.removeAttribute(attribute) 彻底删除属性
  • Node类型定义了attributes属性,针对非Element对象的任何节点该属性为null,对于Element对象,attributes属性是只读的类数组对象,它代表元素的所有属性。可枚举索引,可属性名索引。
document.body.attributes[0]
document.body.attributes.bgcolor
document.body.attributes["ONLOAD"]
  • 表示HTML文档元素的HTML对象定义了读写属性,它们映射了元素的HTML属性。即标签中的属性对应dom对象属性的使用。
var image = document.getElementById('myimage');
var a = image.src;
  • HTML属性名不区分大小写,但JS属性名则大小写敏感。从HTML属性名转换到JS属性名采用小写。若不止一个单词,html样式中名称会采用连接符,则以小驼峰写法
<style>
    div{
        background-color:orange;
        }
</style>

var oDiv = document.getElementsByTagName('div')[0];
oDiv.onclick = function(){
    oDiv.style.backgroundColor = red;
}
  • 有些属性名在JS中是保留字,对于这些属性,一般的命名规则加前缀’html’;这个规则有一个例外,class -> className
<label for= > -> htmlFor   
<a class=>  -> className(特殊) 

5.元素的内容

  • innerHTML (双向功能:获取对象的内容向对象插入内容
    • Object.innerHTML = “HTML”; —– 设置
    • var html = Object.innerHTML; —– 获取
    • 设置可以设置元素标签
    • 获取是起始位置到结束位置内容的全部,包括HTML标签
var a = document.getElementById('aa');
console.log(a.innerHTML);
console.log(a.innerHTML = 'hahaha');
----------------------------------------------------------

function setInnerHTML(){  
    document.getElementById("test").innerHTML = "<strong>点击后改变文字</strong>";  
}  
  • innerText (获取起始位置到终止位置的内容,不包括HTML标签)

    • IE可以使用
    • 它的内容实际上就是你在浏览器看到的内容。它的值是经过浏览器解释过的结果:它将元素的innerHTML换码、解释,最终显示出来,然后去除各种格式信息留下的纯文本。它会把br/换成换行符,会将多个空格并成一个空格对待,而本来的换行符却并不会引起换行,IE会将其当作一个普通的单词边界(一般是空格)。再说的形象点,一个元素的innerText属性的值,和你将这个元素内容复制粘贴到记事本里的内容一致
  • textContent()

    • FF可以使用
    • 它的内容则是innerHTML去除所有标签后的内容(我怀疑这个是从XMLDOM中照搬过来的属性,特性完全一致)。它会将innerHTML中的转义字符(<、 什么的)进行换码,但是不对任何html标签进行解释,而是直接剔除它们。它也不会对innerHTML中的文本按照HTML的方式进行格式转换,比如多个空格还会原原本本地保留,不会合并为一个空格,换行符仍然存在(相反br/却不会导致换行)。
    • 总结:IE中的innerText是需要对innerHTML的值进行:
      1、HTML转义(等同于XML转义,对<、&等转义字符进行处理);
      2、经过HTML解释和CSS样式解释;
      3、之后又剔除格式信息之后留下的纯文本。
      而FF中的textContent没有2、3步,在经过了HTML转义之后直接剔除所有html标签后得到的纯文本。
<div id="T1">
    ABCD EFGHIJ <br>KLM N OPQ
    <div>RS</div>T T
</div>
<script>
    var a = T1.textContent;
    console.log(a);
    var b = T1.innerText;
    console.log(b);
    var c = T1.innerHTML;
    console.log(c);
    var d = T1.outerHTML;
    console.log(d);
</script>

这里写图片描述

  • outerHTML(除了包含innerHTML的内容外,还包括)
<div id="demo">
    <ul>
       <p>P</p>
       <li>TEXT</li>
    </ul>
</div>
<script>
       var a = document.getElementById('demo');
       console.log(a.innerHTML);
<script>

这里写图片描述

6.创建、插入、删除节点

  • document.createElemnet(tag)
  • document.createTextNode(‘text node content’)
  • document.cloneNode()
  • element.appendChild(node)
  • document.insertBefore(‘newNode’,’oldNode’)
  • document.insertAfter()
  • element.removeChild()

属性和特性

技能和天赋
只有特性能让 dom 对象和 html 标签形成一一映射
dom对象可以通过点的方式配置特性,对象怎么改变,标签相应改变
通过js设置普通属性只能用setAttribute(属性名,属性值)

oDiv.id = 
oDiv.setAttribute('click',0)
<div id = 'demo' xxx = 'ddd'>
var oDiv = document.getElementsByTagName('div')[0];

console.log(oDiv.id);
oDiv.id = 'demo1';
oDiv.name = '10';
console.log(oDiv.xxx);
oDiv.setAttribute('xxx', 'ttt');

这里写图片描述
这里写图片描述

  1. 对于div而言,id是特性,可以通过dom对象调用属性的方式映射html标签修改value;name不是div的特性,因此不能产生映射
  2. xxx是属性,不产生映射
  3. 设置任意属性,调用setAttribute方法

DOM节点,构造函数

这里写图片描述

  1. html的标签在JS里叫节点,节点一定是一个对象,是对象就可以在结构树中找到构造函数
  2. document是一个节点, 是一个dom对象 构造函数是HTMLDocument
  3. 如果在Node对象里定义方法,则子节点都可以使用
  4. getElementByTagName方法定义在Document.prototype和Element.prototype上
  5. HTMLDocument.prototype定义了常用的属性 head、body分别指代html的对应标签
  6. Document.prototype上定义了documentElement属性,指代文档的根元素,在HTML文档中,他总是指代html元素
  7. text和comment节点没有children属性,因此Node.parentNode属性不可能返回text和comment节点
<ul id = 'oUl'>
    <li></li>
</ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
document.getElementsByTagName('li');
oUl.getElementsByTagName('li');

这里写图片描述

  • 可以使用封装好的方法在原型上定义新的方法
HTMLDocument.prototype.divArray = document.getElementsByTagName('div');
console.log(document.divArray);
  • 实现输入数字查找父节点
<script>
    Element.prototype.reParent = function(n){
      if( n > 0 ){
        //   var pE = this.parentElement;
        //  注意此处细节,parentNode和parentElement定义在哪个对象中。document可以调用parentNode方法,不能调用parentElement方法。
        var pE = this.parentNode
          for(var i = 0; i < n -1 && pE.nodeType != 9; i++){
              pE = pE.parentNode;
          }
          return pE;
      }else{
          return this;
      }
    }

    function a (){
        for(var i = -1; i < 7; i++){
            console.log(oSpan.reParent(i));
        }
    }
    a();
</script>

这里写图片描述


demo

<body>
    <!-- <div class:'wrapper'>
        <p class="personInfo">
            <span class="name">韩雪</span>
            <span class="search"></span>
        </p>
        <div class="personDes">
            <img src="">
            <p></p>
        </div>
    </div> -->
    <script>
        var personData = [{
            name: '韩雪',
            search: 33333,
            des: '韩雪,1983年出生于江苏省苏州市姑苏区,中国内地女演员,歌手,影视制作人',
            imgSrc: 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1515583292113&di=900b2523cd906076b8e9b767b97c83a1&imgtype=0&src=http%3A%2F%2Fent.iyaxin.com%2Fattachement%2Fjpg%2Fsite2%2F20100106%2F0019667873730cae950c1b.jpg'
        }, {
            name: '江一燕',
            search: '78863',
            des: '江一燕,1983年9月11日出生于浙江省绍兴市,毕业于北京电影学院,中国内地影视女演员',
            imgSrc: 'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=928988968,2706488933&fm=27&gp=0.jpg'
        }]

 function renderPage(data) {
     data.forEach(function(ele, index) {
         var oWrapper = document.createElement('div');
         oWrapper.setAttribute('class', 'wrapper');


         var oInfoP = document.createElement('p');
         oInfoP.setAttribute('class', 'personInfo');

         var oNameSpan = document.createElement('span');
         oNameSpan.setAttribute('class', 'name');
         oNameSpan.innerText = ele.name;

         var oSearchSpan = document.createElement('span');
         oSearchSpan.setAttribute('class', 'search');
         oSearchSpan.innerText = ele.search;
         oInfoP.appendChild(oNameSpan);
         oInfoP.appendChild(oSearchSpan);

         var oDesDiv = document.createElement('div');
         oDesDiv.setAttribute('class', 'personDes');

         var oImg = document.createElement('img');
         oImg.setAttribute('src', ele.imgSrc);
         var oP = document.createElement('p');
         oP.innerText = ele.des;
         oDesDiv.appendChild(oImg);
         oDesDiv.appendChild(oP);
         oWrapper.appendChild(oInfoP);
         oWrapper.appendChild(oDesDiv);
         document.body.appendChild(oWrapper);
     })
 }

 renderPage(personData);

这里写图片描述


2.通过JS创建标签

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
</ul>
<script>
    var oLiArray = document.querySelectorAll('li');
    //var oLiArray1 = document.getElementsByTagName('li');
    console.log(oLiArray);

    var oNewLi = document.createElement('li');
    console.log(oNewLi);

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

    oUl.appendChild(oNewLi);
    console.log(oLiArray);
</script>

这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值