5

JavaScript DOM.png

DOM简介

  • DOM(文档对象模型) 是一项 W3C标准。
  • DOM 模型被结构化为对象树。
  • DOM 本质:从html文件提取出个一棵树。
  • DOM 是关于如何获取、更改、添加或删除 HTML 元素的标准。

Document 对象

文档对象代表您的网页。访问 HTML 页面中的任何元素,总是从访问 document 对象开始。

DOM 节点

节点类型

根据 W3C HTML DOM 标准,HTML 文档中的所有事物都是节点:

  • 整个文档是文档节点
  • 每个 HTML 元素是元素节点
  • HTML 元素内的文本是文本节点
  • 每个 HTML 属性是属性节点
  • 所有注释是注释节点
DOM 处理中的一种常见错误是认为元素节点中包含文本。而应该是元素节点包含了文本节点。

DOM 根节点

有两个特殊属性允许访问完整文档:
document.body:文档的 body
document.documentElement:文档的html(完整文档)

获取文本节点的值

  • 可以通过节点的 innerHTML 属性进行访问。
  • 也可以访问首个子节点的 nodeValue
<title id="demo">DOM 教程</title> 
<script>
//方法一
let myTitle = document.getElementById("demo").innerHTML;
//方法二
let myTitle = document.getElementById("demo").firstChild.nodeValue;
//方法三
let myTitle = document.getElementById("demo").childNodes[0].nodeValue;
</script>

attribute 和 property

DOM有其默认的基本属性,而这些属性就是所谓的property,无论如何,它们都会在初始化的时候再DOM对象上创建。如果在html标签中对这些属性进行赋值,那么这些值就会作为初始值赋给DOM的同名property。

property:是DOM对象上的属性,
attribute:是html标签上的特性:包含自定义属性。有三个方法setAttributegetAttributeremoveAttribute

  • 对于DOM元素节点默认的基本属性,无论哪一方面发生改变,都会互相影响。
  • 对于自定义的属性,任何一方改变都不会影响到另一方。且对于arrtibute设置的自定义属性,会体现到html 结构中,而property 自定义的属性,不会体现到html 结构中。
<div id="div1" class="divClass" title="divTitle" title1="divTitle1">测试</div>
<script>
    let in1 = document.getElementById("div1");
    in1.abcdefg = "abcdefg"; //设置自定义property属性
    in1.setAttribute("att", "aaa"); //设置自定义attribute 属性
    in1.title = "theTitle"; //修改DOM默认属性
    in1.setAttribute("class", "theClass");//修改DOM默认属性
</script>

节点关系

父(parent)、子(child)和同胞(sibling)用于描述这些关系。
在节点之间导航
通过 JavaScript,您可以使用以下节点属性在节点之间导航:

  • parentNode
  • childNodes[nodenumber]
  • firstChild
  • lastChild
  • nextSibling
  • previousSibling

children和childNodes的区别
children:只包含元素节点
childNodes:包含所有类型的节点

节点属性

nodeName 属性

规定节点的名称。只读。总是包含 HTML 元素的大写标签名。
  • 元素节点的 nodeName 等同于标签名
  • 属性节点的 nodeName 是属性名称
  • 文本节点的 nodeName 总是 #text
  • 文档节点的 nodeName 总是 #document

nodeValue 属性

规定节点的值。可写。
  • 元素节点的 nodeValue 是 undefined
  • 文本节点的 nodeValue 是文本文本
  • 属性节点的 nodeValue 是属性值

nodeType 属性

返回节点的类型。只读。

DOM 节点操作

查找 HTML 元素

通过 id 查找 HTML 元素

//查找 id="intro" 的元素:
let myElement = document.getElementById("intro");

通过标签名查找 HTML 元素

//查找 id="main" 的元素,然后查找 "main" 中所有 <p> 元素:
let x = document.getElementById("main");
let y = x.getElementsTagName("p");

通过类名查找 HTML 元素

//返回包含 class="intro" 的所有元素的列表:
let x = document.getElementsByClassName("intro");

通过 CSS 选择器查找 HTML 元素

需要查找匹配指定 CSS 选择器(id、类名、类型、属性、属性值等等)的所有 HTML 元素,请使用 querySelectorAll() 方法。
//返回 class="intro" 的所有 <p> 元素列表:
let x = document.querySelectorAll("p.intro");

通过 HTML 对象集合查找 HTML 元素

//查找 id="frm1" 的 form 元素,在 forms 集合中,然后显示所有元素值:
let x = document.forms["frm1"];
let text = "";
for(let i = 0; i<x.length;i++){
    text += x.elements[i],value+"<br>";
}
document.getElementById("demo").innerHTML = text;
属性 描述 DOM
document.anchros 返回拥有 name 属性的所有 元素。 1
document.body 返回<body>元素 1
document.cookie 返回文档的 cookie 1
document.forms 返回所有 <form> 元素 1
document.images 返回所有 <img> 元素 1
document.title 返回 <title> 元素 1
document.documentElement 返回 <html> 元素 3
document.head 返回 <head> 元素 3
document.scripts 返回所有 <script> 元素 3

改变 HTML

改变 HTML 输出流
document.write() 可用于直接写入 HTML 输出流:千万不要在文档加载后使用 document.write()。这么做会覆盖文档。
改变 HTML 内容
使用 innerHTML 属性。

document.getElementById(id).innerHTML = 'new text'

改变属性的值

document.getElementById("myImage").src = "landscape.jpg";

改变 CSS

语法:
document.getElementById(id).style.property = new style

document.getElementById("p2").style.color = "blue";

DOM 结构操作

如需向 HTML DOM 添加新元素,您必须首先创建这个元素(元素节点),然后将其追加到已有元素。

添加新 HTML 元素(节点)

创建新 HTML 元素(节点)

document.createElement("p");
document.createTextNode("这是新文本。");

追加到已有元素

para.appendChild(node); //追加新元素作为父的最后一个子。
element.insertBefore(para, child);//将para插入到父元素element下的child子元素前面

示例:

<div id="div1">
    <p id="p1">这是一个段落。</p>
    <p id="p2">这是另一个段落。</p>
</div>
<script>
    var para = document.createElement("p");
    var node = document.createTextNode("这是新文本。");
    para.appendChild(node);
    var element = document.getElementById("div1");
    element.appendChild(para);
</script>

删除已有 HTML 元素

如需删除某个 HTML 元素,您需要知晓该元素的父节点。
常见的方法:找到你想要删除的子节点,并利用其 parentNode 属性找到父节点。

示例:

<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另一个段落。</p>
</div>
<script>
//方法一
    let parent = document.getElementById("div1");
    let child = document.getElementById("p1");
    parent.removeChild(child);

//方法二
    let child = document.getElementById("p1");
    child.parentNode.removeChild(child);
</script>

替换 HTML 元素

如需替换元素的,请使用 replaceChild() 方法。

<div id="div1">
    <p id="p1">这是一个段落。</p>
    <p id="p2">这是另一个段落。</p>
</div>

<script>
    let para = document.createElement("p");
    let node = document.createTextNode("这是新文本。");
    para.appendChild(node);

    let parent = document.getElementById("div1");
    let child = document.getElementById("p1");
    parent.replaceChild(para, child);
</script>

DOM 集合与节点列表

DOM集合:HTMLCollection 对象

HTMLCollection 对象是类数组的 HTML 元素列表(集合)。但它并非是数组。无法对 HTMLCollection 使用数组方法,比如 valueOf()、pop()、push() 或 join()。
length 属性定义了 HTMLCollection 中元素的数量。
getElementsByTagName() 方法返回 HTMLCollection 对象。

//下面的代码选取文档中的所有 <p> 元素:
var x = document.getElementsByTagName("p");

DOM 节点列表:NodeList 对象

NodeList 对象是从文档中提取的节点列表(集合)。NodeList 对象与 HTMLCollection 对象几乎相同。
所有浏览器都会为 childNodes 属性返回 NodeList 对象。
大多数浏览器会为 querySelectorAll() 方法返回 NodeList 对象。

HTMLCollection 与 NodeList 的区别

  • HTMLCollection是 HTML 元素的集合。NodeList 是文档节点的集合(元素节点+包含属性节点和文本节点)。
  • 访问 HTMLCollection 项目,可以通过它们的名称、id 或索引号。访问 NodeList 项目,只能通过它们的索引号。

DOM 性能

避免频繁的DOM操作:

采用事件代理避免了频繁的操作DOM

将频繁操作改为一次性操作

let pList = document.getElementsByClassName("para");
let frag = document.createDocumentFragment();
for (let i = 0; i < 5; i++) {
    let span = document.createElement("span");
    span.innerHTML = `${i}`;
    frag.appendChild(span);
}
pList[0].appendChild(frag);

对DOM查询做缓存

// 不缓存DOM查询结果
for (let i = 0; i < document.getElementsByTagName('p').length; i++) {
    //每次循环,都会计算 length ,频繁进行DOM 查询
}
const pList = document.getElementsByTagName('p');
const length = pList.length;
for (let i = 0; i < length; i++) {
    //缓存length,只进行一次DOM查询
}

梁柱
135 声望12 粉丝