DOM 文档对象模型

文档对象模型 DOM

文档对象模型 (DOM) 是表示和操作 HTML 和 XML 文档内容的基础 API.
DOM树: HTML 文档的树状结构包含表示 HTML 标签或元素 (如 、

) 和表示文本字符串的节点.

利用家族图谱可以非常好的形容 HTML 的树状结构

node.png

  • 在一个节点之上的直接节点是其父节点
  • 在其下一层的直接节点是其子节点
  • 在同一层上具有相同父节点的节点是兄弟节点
  • 在一个节点之下的所有层级的一组节点是其后代节点
  • 一个节点的父节点和其上层的所有节点是祖先节点

node 节点

每一个节点表示一个 node 对象

  1. Document: 树形的根部是 Document 节点, 它代表整个文档.

  2. Element: HTML 元素的节点是 Element 节点.

  3. Text: 代表文本的节点是 Text 节点.

选取文档元素

大多数客户端 JavaScript 程序运行时总是在操作一个或多个文档元素.当这些程序启动时,可以使用全局变量 document 来引用 Document 对象.为了操作文档中的元素,我们必须通过某种方式选取元素

通过 ID 选取元素

任何 HTML 元素可以有一个 id 属性,在文档中该值必须唯一.
可以用 Document 对象的 getElementById() 方法选取一个基于 ID 的元素.

  var logo = document.getElementById();
复制代码

通过名字选取元素

HTML 的 name 属性最初打算为表单元素分配名字,在表单数据提交到服务器时使用该属性的值.类似 id 属性,name 是给元素分配名字,但是区别于 id, name 属性的值不是必须唯一.

  var newsList = document.getElementByName("news");
复制代码

返回一个 NodeList 对象数组

通过标签名选取元素

Document 对象的 getElementsByTagName() 方法可用来选取指定类型 (标签名) 所有 HTML 元素.

  var pList = document.getElementsByTagName("p");
复制代码

类型于 getElementByName(), getElementsByTagName() 返回一个 NodeList 对象数组.

通过 CSS 类选取元素

基于 class 属性值中的标识符来选取成组的文档元素.

  var cats = document.getElementsByClassName("cat");
复制代码

getElementsByclassName() 返回一个实时的 NodeList 对象数组

通过 CSS 选择器选取元素

我们通过 CSS 选择器,可以用来准确的描述文档中的若干或多组元素.
同样我们也可以通过 CSS 选择器的语法规则获取一个或一组 HTML 元素.

Document方法 querySelectorAll()querySelector(), 接受一个 CSS 选择器的字符串参数.

  var newsList = document.querySelectorAll(".news");
复制代码

querySelectorAll() 方法返回的 NodeList 对象数组并不是实时的:它包含在调用时刻选择器所匹配的元素,但它并不更新后续文档变化.

区别于 querySelectorAll(), querySelector(), 它返回第一个匹配的元素如果没有匹配的元素返回 null

文档结构和遍历

一旦从文档中选取一个元素,有时需要查找文档中与之在结构上相关的部分(父亲、兄弟和子女).节点类型定义了遍历该树所需的属性.

作为节点树的文档

Document 对象、它的 Element 对象和文档中表示文本的 Text 对象都是 Node 对象.
Node 定义了以下属性:

  • parentNode, 该节点的父节点,或者针对类似 Document 对象应该是 null,因为它没有父节点.

  • childNodes, 只读的类数组对象(NodeList对象),它是该节点的子节点的实时表示.

  • firstChild、lastChild, 该节点的子节点的第一个和最后一个,如果该节点没有子节点则为 null.

  • nextSibling、previousSibling, 该节点的兄弟节点中的前一个和下一个.具有相同父亲节点的两个节点为兄弟节点.节点的顺序反映了它们在文档中出现的顺序.

  • nodeType, 该节点的类型. 9 代表 Document 节点, 1 代表 Element 节点, 3 代表 Text 节点, 8 代表 Comment 节点, 11 代表 DocumentFragemnt 节点.

  • nodeValue, Text 节点或 Comment 节点的文本内容.

  • nodeName, 元素的标签名,以大写形式表示.

作为元素树的文档

当将主要的兴趣点集中在文档中的元素上而非它们之间的文本上时,我们可以使用另一个更用用的 API. 它将文档看做是 Element 对象树.

属性

HTML 元素有一个标签和一组称为属性的名/值对组成. HTML 元素的属性值在代表这些元素的 HTMLElement 对象的属性(property) 中是可用的.

HTML 属性作为 Element 的属性

表示 HTML 文档元素的 HTMLElement 对象定义了读/写属性,它们映射了元素的 HTML 属性.
例如,查询一张图片的 URL, 可以使用表示元素的 HTMLElement 对象的 src 属性:

  var image = document.getElementById("logo");
  var logoUrl = image.src; // src 属性是图片的 URL
复制代码

同样,可以为一个

元素设置表单提交的属性:

  var form = document.forms[0]; // 文档中第一个 form 
  form.action = "http://www.baidu.com";
  form.method = "GET";
复制代码

有些 HTML 属性名在 JavaScript 中是保留字.对于这些属性,一般的规则是为属性名加前缀“html”.
例如, HTML 中的 for 属性(lable 元素) 在 JavaScript 中变为 htmlFor.
class 属性是一个例外,在 JavaScript 中它变为 classname.

 var lable = document.getElementsByTagName("lable")[0];
 lable.htmlFor === "name";
 lable.classname = "form-name";
复制代码

获取和设置非标准 HTML 属性

Element 类型还定义了 getAttribute() 和 setAttribute() 方法来查询和设置非标准的 HTML 属性.

  var image = document.images[0];
  var width = parseInt(image.getAttribute("width"));
复制代码

对于 HTML 元素来说,属性名不区分大小写

Element 类型还定义了两个相关的方法, hasAttribute() 和 removeAttribute(), 它们用来检测命名属性是否存在和完全删除属性.

数据集属性

HTML5 中,任意以 “data-” 为前缀的小写的属性名字都是合法的.这些“数据集属性”将不会对其元素的表现产生影响,它们定义了一种标准、附加额外数据的方法,并不是在文档合法性上做出让步.

HTML5 还在 Element 对象上定义了 dataset 属性. 该属性指代一个对象,它的各个属性对应于去掉前缀的 data- 属性.带连字符的属性对应于驼峰命名法属性名: data-name-a 属性就变成 dataset.nameA 属性.

作为 Attr 节点的属性

对于 Element 对象, attributes 属性是只读的类数组对象,它代表元素的所有属性.attributes 对象是实时的.

  document.body.attributes[0]; // <body> 元素的第一个属性
  document.body.attributes.bgcolor // <body> 元素的 background 属性
  document.body.attributes["onload"] // <body> 元素的 onload 属性
复制代码

元素的内容

  • 内容是 HTML 字符串
  • 内容是纯文本字符串
  • 内容是一个 Text 节点、一个节点包含一个 Text 子节点的 Elemnt 节点和另一个 Text 节点.

作为 HTML 的元素内容

读取 Element 的 innerHTML 属性作为字符串标记返回那个元素的内容.在元素上设置该属性调用了 Web 浏览器的解析器,用新字符串内容的解析展现形式替换元素当前内容.
Web 浏览器很擅长解析 HTML,通常设置 innerHTML 效率非常高,甚至在指定的值需要解析时效率也是相当不错的.但注意,对 innerHTML 属性用 “+=”操作符重复添加一段内容通常效率低下,因为他要序列化又要解析.

作为纯文本的元素内容

有时需要查询纯文本形式的元素内容,或者在文档中插入纯文本(不必转译HTML标签中使用的尖括号和&符号).标准的方法是用 Node 的 textContent 属性来实现:

  var para = document.getElementByTagName("p")[0];
  var text = para.textContent;
  para.textContent = "have a good time!";
复制代码

作为 Text节点的元素内容

当考虑元素的内容时,通常感兴趣的是它的 Text 节点.

创建、插入和删除节点

Document 类型定义了创建 Element 和 Text 对象的方法, Node 类型定义了节点树中插入、删除和替换的方法.

创建节点

创建新的 Element 节点可以使用 Document 对象的 createElement() 方法. 给方法传递标签名.

  var newElement = document.createElement("DIV"); // html 不区分大小写
复制代码

Text 节点用类似的方法创建:

 var newNode = document.createTextNode("text node content");
复制代码

复制已存在的节点.每个节点有一个 cloneNode() 方法来返回该节点的一个全新副本:

  var div = document.getElementsByTagName("div")[0];
  div.cloneNode(); // 默认浅复制
  div.cloneNode(true); // 传递 true ,递归复制所有后代子节点
复制代码

插入节点

  • appendChild() 方法是在需要插入的 Elemnet 节点上调用的,它插入指定的节点使其称为那个节点的最后一个子节点.

  • insertBefore() 方法接受两个参数,第一个参数是带插入的新节点,第二个参数是已存在的节点,新节点插入到该节点的前面,如果传递 null 作为第二个参数,insertBefore() 的行为类似 appendChild().

删除和替换节点

  • removeChild() 方法是从文档树中删除一个节点.不是在待删除的节点上调用,而是删除该节点的子节点.

假设删除 n 节点:

  n.parentNode.removeChild(n);
复制代码
  • replaceChild() 方法删除一个子节点并用一个新的节点取而代之.
  n.parentNode.replaceChild(document.createTextNode("hello"), n);
复制代码

使用 DocumentFragment

DocumentFragment 是一种特殊的 Node, 它作为其他节点的一个临时容器.
DocumentFragment 的特殊指出在于它使得一组节点被被当做一个节点看待: 如果给 appendChild()、insertBefore() 或 replaceChild() 传递一个 DocumentFragment,其实是将该文档片段的所有子节点插入到文档中,而非片段本身.
与document相比,最大的区别是DocumentFragment 不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。

DocumentFragment 应用(MDN):

  const list = document.querySelector('#list');
  const fruits = ['Apple', 'Orange', 'Banana', 'Melon'];

  const fragment = document.createDocumentFragment();

  fruits.forEach(fruit => {
    const li = document.createElement('li');
    li.innerHTML = fruit;
    fragment.appendChild(li);
  });

  list.appendChild(fragment);
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享