介绍

文档对象模型(DOM,Document Object Model)是 HTML 和 XML 文档的编程接口。

脱胎于网景和微软早期的动态 HTML(DHTML,Dynamic HTML),DOM 现在是真正跨平台、语言无关的表示和操作网页的方式。

image.png

简单的说,DOM,就是帮助你通过JS,去操作HTML元素,如

改变页面中的所有 HTML 元素、HTML 属性;
改变页面中的所有 CSS 样式;
添加、删除 HTML 元素和属性;
对页面中所有已有的 HTML 事件作出反应;
在页面中创建新的 HTML 事件;
等等

DOM架构设计

image.png

================

EventTarget 事件对象

主要有3个方法,所有DOM里面的对象都继承这个对象,因此大家都有这三种方法可以调用
image.png
MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/Events
image.png

Node 节点对象

所有节点,都继承自 Node节点对象,因此都有节点的属性和方法,
如nodeName 节点名、firstChild 第一个子节点等等属性;
如appendChild( ) 添加子节点方法等等;

可以查看MDN文档,不用刻意去记,但是要知道哪里可以查到:https://developer.mozilla.org/zh-CN/docs/Web/API/Node
image.png

Document 网页对象

说明

Document节点表示的整个载入的网页,如下图,所有整个都是 Document节点,也就是标签内的所有元素。
image.png

每个文档只能有一个标签,所有的元素都是以树型的数据结构,他们的根就是标签。

image.png
MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Document

document 是 window对象的属性,因此是一个全局对象,可以直接用document ,而不用 window.document 。

常见属性

1、文档标题(浏览器标签标题)
image.png
image.png
2、head标签 和 body标签
image.pngimage.png
image.png image.png

3、子元素合集,只要是合集,都是HTMLCollection类型,类似数组
image.png
image.png
4、也有location属性,就是当前文档输入的链接url,和window (BOM)的是同一个
image.pngtrue

常用方法

1、创建元素
image.png
本质上上面两种方式是一样的,第一个方式内部也是帮你new 一个元素

2、获取元素
image.png
这里简单介绍,详细操作见下

原生操作DOM

https://www.yuque.com/yejielin/mypn47/zr9hho#Ge1OJ
现在比较少原生操作DOM,一个是API比较长且多,不好操作,后来是通过JQuery,现在主要是通过前端三大框架(Vue、React、Angular)帮我们操作

Element 元素对象

说明

我们平时创建的div、p、span等元素在DOM中表示为Element元素对象,有对应的属性和方法

MDN文档,不用可以记,但是要知道在哪里可以查:https://developer.mozilla.org/zh-CN/docs/Web/API/Element

常用属性和方法

image.png

1、元素属性操作

  1. //<div id="myDiv" my_special_attribute="hello!"></div> 自定义一个属性
  2. let div = document.getElementById("myDiv");
  3. // ============ 1、获取属性 ============
  4. // 这种只能获取公认的 DOM 对象的属性,不能获取自定义属性
  5. let id = div.id; // myDiv
  6. // 主要可以获取自定义的属性
  7. let value = div.getAttribute("my_special_attribute"); // hello!
  8. // 获取属性集合,该集合是一个 NamedNodeMap 对象,不是一个数组,所以它没有 数组 的方法
  9. let divAttr = div.attributes;
  10. for(var i=divAttr.length-1; i>=0; i--) { // 可以遍历获取属性和值
  11. console.log(divAttr[i].name + " : " + divAttr[i].value;)
  12. }
  13. // ============ 2、设置属性 ============
  14. // 如果属性已经存在,则 setAttribute()会以指定的值替换原来的值;
  15. // 如果属性不存在,则 setAttribute()会以指定的值创建该属性。
  16. div.setAttribute("my_special_attribute", "123123");
  17. // ============ 3、删除属性 ============
  18. div.removeAttribute("my_special_attribute");

3、元素后代 childNodes

childNodes属性包含元素所有的子节点,这些子节点可能是其他元素、文本节点、注释或处理指令。
不同浏览器在识别这些节点时的表现有明显不同。

  1. <ul id="myList">
  2. <li>Item 1</li>
  3. <li>Item 2</li>
  4. <li>Item 3</li>
  5. </ul>
  6. <!--
  7. 在解析以上代码时,<ul>元素会包含 7 个子元素,其中 3 个是<li>元素,还有 4 个 Text 节点(表示<li>元素周围的空格)。
  8. 如果把元素之间的空格删掉,变成下面这样,则所有浏览器都会返回同样数量的子节点:
  9. -->
  10. <ul id="myList"><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>

考虑到这种情况,通常在执行某个操作之后需要先检测一下节点的 nodeType

  1. for (let i = 0, len = element.childNodes.length; i < len; ++i) {
  2. if (element.childNodes[i].nodeType == 1) { // nodeType == 1是Element 元素节点
  3. // 执行某个操作
  4. }
  5. }

CharacterData 字符数据对象

主要包含 Text 文本对象,和 Comment 注释对象。

操作文本和注释的方法,基本都是这个对象提供

MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/API/CharacterData

Text 文本对象

包含按字面解释的纯文本,也可能包含转义后的 HTML 字符,但不包含 HTML 代码。

只要开始标签和结束标签之间有内容,就会创建一个文本节点,最多也就是只有1个文本节点,里面不支持子节点。

  1. <!-- 没有内容,因此没有文本节点 -->
  2. <div></div>
  3. <!-- 有空格,因此有一个文本节点 -->
  4. <div> </div>
  5. <!-- 有内容,因此有一个文本节点 -->
  6. <div>Hello World!</div>

常见操作

继承自CharacterData 字符数据对象,大部分方法都是 CharacterData 字符数据对象 提供

  1. // <div id='test'>Hello World!</div>
  2. let div = document.getElementById("test");
  3. // =============== 0、获取文本节点 ===============
  4. let textNode = div.firstChild; // 或 div.childNodes[0]
  5. // =============== 1、获取文本值 ===============
  6. textNode.nodeValue // "Hello World!"
  7. textNode.data // "Hello World!"
  8. // 文本的长度
  9. textNode.nodeValue.length //12
  10. textNode.data.length // 12
  11. // =============== 2、修改 ===============
  12. // 修改,只要节点在当前的文档树中,这样的修改就会马上反映出来
  13. textNode.nodeValue = 'new World' // 直接改
  14. textNode.appendData("!") // 末尾追加, new World!
  15. // =============== 3、创建 & 合并 ===============
  16. // 一般来说一个元素只包含一个文本子节点,
  17. // 如果添加多个文本子节点,那么需要用element.normalize();方法合并一起,中间没有空格
  18. let anotherTextNode = document.createTextNode("Yippee!"); // 创建另一个文本节点
  19. div.appendChild(anotherTextNode); // 加进去,浏览器在解析文档时,永远不会创建同胞文本节点。
  20. div.normalize(); // 合并2个文本子节点, new World!Yippee!
  21. // =============== 4、插入 ===============
  22. textNode.insertData(0, "A ") // 在位置 0个字符的位置后插入 A ,A new World!Yippee!
  23. // =============== 5、拆分 / 提取 ===============
  24. let newNode = textNode.splitText(12); // 拆分,12是偏移量,从左算起第12个位置, newNode = "A new World!"
  25. textNode; // Yippee!
  26. // =============== 6、删除 ===============
  27. textNode.deleteData(0, 1) // 从位置第0个字符右边 开始删除 1 个字符, ippee!
  28. textNode.replaceData(0, 1, "text") // 用 text 替换从第0个字符右边到 第1个字符右边;pppee!

其他对象

image.png
都可以在Node节点的MDN文档里面查到,其他用的不多

=================

虚拟节点

  1. let list = document.getElementById("myList"),
  2. fragment = document.createDocumentFragment(), // 创建虚拟节点
  3. item;
  4. for (let i = 0; i < 10; i++) {
  5. item = document.createElement("li");
  6. // 1、使用虚拟节点构建 DOM 结构,此时不会显示在DOM界面上
  7. fragment.appendChild(item);
  8. item.appendChild(document.createTextNode("Item " + i));
  9. }
  10. // 2、然后一次性将它添加到 list 元素,减少DOM的更新,优化性能
  11. list.appendChild(fragment);

=================

Dom编程

==================

观察DOM元素变化接口

==================

性能

1、尽量少访问DOM和尽量减少标记

因为访问DOM查询某个元素,都会检索一次DOM树。
优化就是存储搜索的结果(赋值给变量),然后重复使用。

2、尽量减少标记

标记多,检索一次耗时就长。

3、合并和放置脚本

image.png
减少请求。

4、脚本的位置

image.png
放在末尾以及之前

5、压缩脚本

不必要的字节、空格、注释删除,很多工具可以帮忙做到,比如很多min.js