# dom

⬅️js一些经典常用功能 | 参考阅读window对象

DOM

或文档对象模型是 web 页面上所有对象的根。它表示文档的结构,并将页面连接到编程语言。它的结构是一个逻辑树。每个分支结束于一个节点,每个节点包含子节点、对象。
整个文档是一个文档节点,就想是树的根一样。
每个HTML元素都是元素节点。
HTML元素内的文本就是文本节点。
每个HTML属性时属性节点。

# 系统介绍document对象

🔝🔝 dom

属性 / 方法 描述
document.activeElement 返回当前获取焦点元素
document.addEventListener() 向文档添加句柄
document.adoptNode(node) 从另外一个文档返回 adapded 节点到当前文档。
document.anchors 返回对文档中所有 Anchor 对象的引用。
document.applets 返回对文档中所有 Applet 对象的引用。注意: HTML5 已不支持 <applet> 元素。
document.baseURI 返回文档的绝对基础 URI
document.body 返回文档的body元素
document.close() 关闭用 document.open() 方法打开的输出流,并显示选定的数据。
document.cookie 设置或返回与当前文档有关的所有 cookie。
document.createAttribute() 创建一个属性节点
document.createComment() createComment() 方法可创建注释节点。
document.createDocumentFragment() 创建空的 DocumentFragment 对象,并返回此对象。
document.createElement() 创建元素节点。
document.createTextNode() 创建文本节点。
document.doctype 返回与文档相关的文档类型声明 (DTD)。
document.documentElement 返回文档的根节点
document.documentMode 返回用于通过浏览器渲染文档的模式
document.documentURI 设置或返回文档的位置
document.domain 返回当前文档的域名。
document.domConfig 已废弃。返回 normalizeDocument() 被调用时所使用的配置。
document.embeds 返回文档中所有嵌入的内容(embed)集合
document.forms 返回对文档中所有 Form 对象引用。
document.getElementsByClassName() 返回文档中所有指定类名的元素集合,作为 NodeList 对象。
document.getElementById() 返回对拥有指定 id 的第一个对象的引用。
document.getElementsByName() 返回带有指定名称的对象集合。
document.getElementsByTagName() 返回带有指定标签名的对象集合。
document.images 返回对文档中所有 Image 对象引用。
document.implementation 返回处理该文档的 DOMImplementation 对象。
document.importNode() 把一个节点从另一个文档复制到该文档以便应用。
document.inputEncoding 返回用于文档的编码方式(在解析时)。
document.lastModified 返回文档被最后修改的日期和时间。
document.links 返回对文档中所有 Area 和 Link 对象引用。
document.normalize() 删除空文本节点,并连接相邻节点
document.normalizeDocument() 删除空文本节点,并连接相邻节点的
document.open() 打开一个流,以收集来自任何 document.write() 或 document.writeln() 方法的输出。
document.querySelector() 返回文档中匹配指定的CSS选择器的第一元素
document.querySelectorAll() document.querySelectorAll() 是 HTML5中引入的新方法,返回文档中匹配的CSS选择器的所有元素节点列表
document.readyState 返回文档状态 (载入中……)
document.referrer 返回载入当前文档的文档的 URL。
document.removeEventListener() 移除文档中的事件句柄(由 addEventListener() 方法添加)
document.renameNode() 重命名元素或者属性节点。
document.scripts 返回页面中所有脚本的集合。
document.strictErrorChecking 设置或返回是否强制进行错误检查。
document.title 返回当前文档的标题。
document.URL 返回文档完整的URL
document.write() 向文档写 HTML 表达式 或 JavaScript 代码。
document.writeln() 等同于 write() 方法,不同的是在每个表达式之后写一个换行符。

# querySelector

🔝🔝 doc

  • querySelector() 方法返回文档中匹配指定 CSS 选择器的一个元素。
    • 注意: querySelector() 方法仅仅返回匹配指定选择器的第一个元素。如果你需要返回所有的元素,请使用 querySelectorAll() 方法替代
  • 返回值:匹配指定 CSS 选择器的第一个元素。 如果没有找到,返回 null。如果指定了非法选择器则 抛出 SYNTAX_ERR 异常。
document.querySelector("p");//获取文档中第一个 <p> 元素
document.querySelector(".example");//获取文档中 class="example" 的第一个元素
document.querySelector("p.example");//获取文档中 class="example" 的第一个 <p> 元素
document.querySelector("a[target]");//获取文档中有 "target" 属性的第一个 <a> 元素
1
2
3
4

以下实例演示了多个选择器的使用方法。
假定你选择了两个选择器: <h2> 和 <h3> 元素。

以下代码将为文档的第一个 <h2> 元素添加背景颜色

<h2>A h2 element</h2>
<h3>A h3 element</h3>

document.querySelector("h2, h3").style.backgroundColor = "red";
1
2
3
4

但是,如果文档中 <h3> 元素位于 <h2> 元素之前<h3> 元素将会被设置指定的背景颜色

<h3>A h3 element</h3>
<h2>A h2 element</h2>

document.querySelector("h2, h3").style.backgroundColor = "red";
1
2
3
4

# URL

🔝🔝 doc

  • URL 属性可返回当前文档的 URL。
document.URL
1

# getElementsByTagName

🔝🔝 doc

  • getElementsByTagName() 方法可返回带有指定标签名的对象的集合。(参数值 "*" 返回文档的所有元素。)
  • 返回值:NodeList 对象——指定标签名的元素集合

# getElementById

🔝🔝 doc

  • getElementById() 方法可返回对拥有指定 ID 的第一个对象的引用。
  • HTML DOM 定义了多种查找元素的方法,除了 getElementById() 之外,还有 getElementsByName()getElementsByTagName()
  • 如果没有指定 ID 的元素返回 null
  • 如果存在多个指定 ID 的元素则返回第一个。
  • 如果需要查找到那些没有 ID 的元素,你可以考虑通过CSS选择器使用 querySelector()

# createTextNode

🔝🔝 doc

//createTextNode() 可创建文本节点。
document.createTextNode(text)
1
2
var h=document.createElement("H1")
var t=document.createTextNode("Hello World");
h.appendChild(t);
1
2
3

# document.createElement

🔝🔝 doc

//createElement() 方法通过指定名称创建一个元素
document.createElement(nodename)
1
2

nodename——String——必须。创建元素的名称。

var btn=document.createElement("BUTTON");
var t=document.createTextNode("CLICK ME");
btn.appendChild(t);
1
2
3

# 什么是DOM及DOM操作

back

<!DOCTYPE html>
<html lang="en">
<head>
    <title>A super simple title!</title>
</head>
<body>
<h1>A super simple web page!</h1>
</body>
</html>
1
2
3
4
5
6
7
8
9

在这个结构的顶部有一个document,也称为根元素,它包含另一个元素:htmlhtml元素包含一个head,而 head 又有一个title。 然后body 包含一个h1。 每个HTML元素都由特定类型(也称为接口)表示,并且可能包含文本或其他嵌套元素:

document (HTMLDocument)
  |
  | --> html (HTMLHtmlElement)
          |  
          | --> head (HtmlHeadElement)
          |       |
          |       | --> title (HtmlTitleElement)
          |                | --> text: "A super simple title!"
          |
          | --> body (HtmlBodyElement)
          |       |
          |       | --> h1 (HTMLHeadingElement)
          |              | --> text: "A super simple web page!"
1
2
3
4
5
6
7
8
9
10
11
12
13

每个HTML元素都来自Element,但其中很大一部分都是专用的。 咱们可以检查原型以查找元素所属的“种类”。 例如,h1元素是HTMLHeadingElement

document.querySelector('h1').__proto__

// Output: HTMLHeadingElement
1
2
3

而HTMLHeadingElement则是HTMLElement的后代:

document.querySelector('h1').__proto__.__proto__

// Output: HTMLElement
1
2
3

# document 和 window 之间的区别

back

简单来说,document是window的一个对象属性window 对象表示浏览器中打开的窗口。如果文档包含框架(frame 或 iframe 标签),浏览器会为 HTML 文档创建一个 window 对象,并为每个框架创建一个额外的 window 对象。所有的全局函数和对象都属于 window 对象的属性和方法。

  • window 指窗体document指页面。document是window的一个子对象。
  • 用户不能改变 document.location(因为这是当前显示文档的位置)。但是,可以改变window.location (用其它文档取代当前文档)window.location本身也是一个对象,而document.location不是对象。

document接口有许多实用方法,比如querySelector(),它是用于查找给定页面内HTML元素的方法:

document.querySelector('h1');
1

window表示当前的浏览器,下面代码与上面等价:

window.document.querySelector('h1');
1

window是一个全局对象,可以从浏览器中运行的任何JS代码直接访问。 window暴露了很多属性和方法,如:

window.alert('Hello world'); // Shows an alert
window.setTimeout(callback, 3000); // Delay execution
window.fetch(someUrl); // make XHR requests
window.open(); // Opens a new tab
window.location; // Browser location
window.history; // Browser history
window.navigator; // The actual user agent
window.document; // The current page
1
2
3
4
5
6
7
8

因为这些属性和方法也是全局的,所以也可以这样访问它们

alert('Hello world'); // Shows an alert
setTimeout(callback, 3000); // Delay execution
fetch(someUrl); // make XHR requests
open(); // Opens a new tab
location; // Browser location
history; // Browser history
navigator; // The actual user agent
document;// The current page
1
2
3
4
5
6
7
8

其中有些咱们都已经很熟悉了,如setTimeout() 的方法。 例如,当咱们想要得知当前用户的浏览器语言时,window.navigator就非常有用:

if (window.navigator) {
  var lang = window.navigator.language;
  if (lang === "en-US") {
    // show something
  }

  if (lang === "it-IT") {
    // show something else
  }
}
1
2
3
4
5
6
7
8
9
10

# DOM常用方法

back

# 获取节点

// 通过id号来获取元素,返回一个元素对象
document.getElementById(idName);
// 通过name属性获取id号,返回元素对象数组
document.getElementsByName(name)  
// 通过class来获取元素,返回元素对象数组
document.getElementsByClassName(className);
// 通过标签名获取元素,返回元素对象数组
document.getElementsByTagName(tagName);
1
2
3
4
5
6
7
8

# 获取/设置元素的属性值

// 括号传入属性名,返回对应属性的属性值
element.getAttribute(attributeName);
// 传入属性名及设置的值
element.setAttribute(attributeName,attributeValue);
1
2
3
4

# 创建节点Node

// 创建一个html元素,这里以创建h3元素为例
document.createElement("h3");
// 创建一个文本节点;
document.createTextNode(String);
// 创建一个属性节点,这里以创建class属性为例
document.createAttribute("class");
1
2
3
4
5
6

# 增添节点

// 往element内部最后面添加一个节点,参数是节点类型
element.appendChild(Node);
// 在element内部的中在existingNode前面插入newNode
elelment.insertBefore(newNode,existingNode);
1
2
3
4

# DOM常用属性

back

  • 获取当前元素的父节点
// 返回当前元素的父节点对象
element.parentNode;
1
2
  • 获取当前元素的子节点
// 返回当前元素所有子元素节点对象,只返回HTML节点
element.chlidren;
// 返回当前元素多有子节点,包括文本,HTML,属性节点。(回车也会当做一个节点)
element.chilidNodes;
// 返回当前元素的第一个子节点对象
element.firstChild;
// 返回当前元素的最后一个子节点对象
element.lastChild;
1
2
3
4
5
6
7
8
  • 获取当前元素的同级元素
// 返回当前元素的下一个同级元素 没有就返回null
element.nextSibling;
// 返回当前元素上一个同级元素 没有就返回 null
element.previousSibling;
1
2
3
4
  • 获取当前元素的文本
// 返回元素的所有文本,包括html代码
element.innerHTML;
// 返回当前元素的自身及子代所有文本值,只是文本内容,不包括html代码
element.innerText;
1
2
3
4
  • 获取当前节点的节点类型
// 返回节点的类型,数字形式(1-12)
// 常见几个1:元素节点,2:属性节点,3:文本节点。
node.nodeType
1
2
3
  • 设置样式
// 设置元素的样式时使用style
element.style.color=“#eea”;
1
2

# DOM操作

back

  • DOM中的每个HTML元素也是一个节点,可以像这样查找节点:
document.querySelector('h1').nodeType;
//上面会返回1,它是Element类型的节点的标识符,还可以检查节点名称:
document.querySelector('h1').nodeName;
//"H1"
1
2
3
4

咱们主要使用DOM中的两种类型的节点:

元素节点
文本节点

//创建元素节点,可以通过 createElement方法:
var heading = document.createElement('h1');
//创建文本节点,可能通过 createTextNode 方法:
var text = document.createTextNode('Hello world');
//接着将两个节点组合在一起,然后添加到 body 上:
heading.appendChild(text);
document.body.appendChild(heading)
1
2
3
4
5
6
7

# 13个需要知道的方法:使用 JavaScript 来操作 DOM

back

# document.querySelector / document.querySelectorAll

  • document.querySelector方法返回文档中与指定选择器或选择器组匹配的第一个 html 元素。如果找不到匹配项,则返回null。
  • document.querySelectorAll 方法返回与指定的选择器组匹配的文档中的元素列表 (使用深度优先的先序遍历文档的节点)。返回的对象是 NodeList 。
// 返回第一个 ul 元素
const list = document.querySelector('ul')
// 返回所有类名为 info 或者 warning 的 div 元素
const elements = document.querySelectorAll('div.info, div.warning');
1
2
3
4

# document.createElement2

在一个 HTML 文档中, document.createElement(tagName) 方法创建由 tagName 指定的 HTML 元素,或一个HTMLUnknownElement,如果tagName不被识别。

# Node.appendChild

Node.appendChild()方法将节点添加到给定父节点的子节点列表的末尾。请注意,如果给定的子代是文档中现有节点的引用,则它将移动到新位置。看看示例:

let list = document.createElement('ul');
['北京', '上海', '深圳'].forEach(city => {
  let listItem = document.createElement('li')
  listItem.innerText = city
  list.appendChild(listItem)
})
document.body.appendChild(list)
1
2
3
4
5
6
7

# Node.insertBefore

此方法在给定的父节点内的子引用节点之前插入给定节点(并返回插入的节点)

let list = document.querySelector('ul');
    let firstCity = list.querySelector('ul > li');
    let newCity = document.createElement('li');
    newCity.textContent = 'San Francisco';
    list.insertBefore(newCity, firstCity);
1
2
3
4
5

# Node.removeChild

Node.removeChild方法从DOM中删除一个子节点并返回删除的节点。请注意,返回的节点不再是DOM的一部分,而是仍存在于内存中。如果处理不当,可能会导致内存泄漏

let list = document.querySelector('ul');
let firstItem = list.querySelector('li');
let removedItem = list.removeChild(firstItem);
1
2
3

# Node.replaceChild

此方法替换父节点中的子节点(并返回替换后的旧子节点)。请注意,如果处理不当,此方法可能导致与Node.removeChild类似的内存泄漏问题。

let list = document.querySelector('ul');
let oldItem = list.querySelector('li');
let newItem = document.createElement('li');
newItem.innerHTML = '前端小智';
let replacedItem = list.replaceChild(newItem, oldItem);
1
2
3
4
5

# Node.cloneNode

Node.cloneNode(deep) 方法返回调用该方法的节点的一个副本,**deep(可选)**表示是否采用深度克隆,如果为true,则该节点的所有后代节点也都会被克隆,如果为false,则只克隆该节点本身.

let list = document.querySelector('ul');
let clone = list.cloneNode();
1
2

# Element.getAttribute / Element.setAttribute

Element.getAttribute方法返回元素上给定属性的值,反之亦然,Element.setAttribute设置给定元素上属性的值。

let list = document.querySelector('ul');
list.setAttribute('id', 'my-list');
let id = list.getAttribute('id');
console.log(id); // outputs my-list
1
2
3
4

# Element.hasAttribute / Element.removeAttribute

Element.hasAttribute方法检查给定元素是否具有指定的属性,返回值为boolean。通过调用Element.removeAttribute方法,我们可以从元素中删除具有给定名称的属性。

let list = document.querySelector('ul');
if (list.hasAttribute('id')) {
    console.log('list has an id');
    list.removeAttribute('id');
};
1
2
3
4
5

# Element.insertAdjacentHTML

element.insertAdjacentHTML(position, text) 将指定的文本解析为HTML或XML,并将结果节点插入到DOM树中的指定位置。它不会重新解析它正在使用的元素,因此它不会破坏元素内的现有元素。这避免了额外的序列化步骤,使其比直接innerHTML操作更快。

  • position是相对于元素的位置,并且必须是以下字符串之一:
    • beforebegin:元素自身的前面。
    • afterbegin:插入元素内部的第一个子节点之前。
    • beforeend:插入元素内部的最后一个子节点之后。
    • afterend:元素自身的后面。
  • text是要被解析为HTML或XML,并插入到DOM树中的字符串。
<!-- beforebegin -->
<div>
  <!-- afterbegin -->
  <p>Hello World</p>
  <!-- beforeend -->
</div>
<!-- afterend -->
1
2
3
4
5
6
7
var list = document.querySelector('ul');
list.insertAdjacentHTML('afterbegin', '<li id="first-item">First</li>');
1
2

# Dom 节点和 元素 有啥区别

DOM文档由节点层次结构组成。每个节点可以具有父级和/或子级

<!DOCTYPE html>
<html>
  <head>
    <title>My Page</title>
  </head>
  <body>
    <!-- Page Body -->
    <h2>My Page</h2>
    <p id="content">Thank you for visiting my web page!</p>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
  • <html>是文档树中的一个节点。它有2个子节点:<head>和<body>
  • <body>子有3个子节点的节点:注释节点 <!-- Page Body -->,标题<h2>,段落<p><body>节点的父节点是<html>节点。
  • HTML文档中的标记代表一个节点,有趣的是普通文本也是一个节点。段落节点<p>有1个子节点:文本节点“Thank you for visiting my web page!”

# 节点类型

在于DOM Node接口,尤其是Node.nodeType属性。

  • Node.ELEMENT_NODE
  • Node.ATTRIBUTE_NODE
  • Node.TEXT_NODE
  • Node.CDATA_SECTION_NODE
  • Node.PROCESSING_INSTRUCTION_NODE
  • Node.COMMENT_NODE
  • Node.DOCUMENT_NODE
  • Node.DOCUMENT_TYPE_NODE
  • Node.DOCUMENT_FRAGMENT_NODE
  • Node.NOTATION_NODE
const paragraph = document.querySelector('p');

paragraph.nodeType === Node.ELEMENT_NODE; // => true
1
2
3

代表整个节点文档树的节点类型为Node.DOCUMENT_NODE:

document.nodeType === Node.DOCUMENT_NODE; // => true
1

元素是节点的子类型,就像猫是动物的子类型一样

节点类型的以下属性评估为一个节点或节点集合(NodeList):

node.parentNode; // Node or null

node.firstChild; // Node or null
node.lastChild;  // Node or null

node.childNodes; // NodeList
1
2
3
4
5
6

但是,以下属性是元素或元素集合(HTMLCollection):

node.parentElement; // HTMLElement or null

node.children;      // HTMLCollection
1
2
3

由于node.childNodesnode.children都返回子级列表,因此为什么要同时具有这两个属性?

const paragraph = document.querySelector('p');

paragraph.childNodes; // NodeList:       [HTMLElement, Text]
paragraph.children;   // HTMLCollection: [HTMLElement]
1
2
3
4

paragraph.childNodes集合包含2个节点:<b>Thank you</b>,,以及for visiting my web page!文本节点!

但是,paragraph.children集合仅包含1个项目:<b>Thank you</b>

由于paragraph.children仅包含元素,因此此处未包含文本节点,因为其类型是文本(Node.TEXT_NODE),而不是元素(Node.ELEMENT_NODE)。

同时拥有node.childNodes和node.children,我们可以选择要访问的子级集合:所有子级节点或仅子级是元素。