DOM

179 阅读7分钟

基本介绍

image.png

获取节点

image.png

image.png

image.png

image.png

image.png

image.png

操作节点

image.png

创建节点

document.createElement(tag)
用给定的标签创建一个新 元素节点(element node):

let div = document.createElement('div');

document.createTextNode(text)
用给定的文本创建一个 文本节点:

let textNode = document.createTextNode('Here I am');

插入.删除.替换节点

一.
node.append(...nodes or strings) — 在 node 末尾插入
node.prepend(...nodes or strings) — 在 node 开头插入
node.before(...nodes or strings) — 在 node 之前插入
node.after(...nodes or strings) — 在 node 之后插入
node.replaceWith(...nodes or strings) — 替换 node
node.remove() — 移除 node
文本字符串被“作为文本”插入


二.
parent.appendChild(node)
parent.insertBefore(node, nextSibling)
parent.removeChild(node)
parent.replaceChild(newElem, node)
这些方法都返回 node

克隆节点

cloneNode
调用 elem.cloneNode(true) 来创建元素的一个“深”克隆 — 具有所有特性(attribute)和子元素。如果我们调用 elem.cloneNode(false) ,那克隆就不包括 子元素。

<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<div class="alert" id="div">
<strong>Hi there!</strong> You've read an important message.
DocumentFragment 是一个特殊的 DOM 节点,用作来传递节点列表的包装器
(wrapper)。
我们可以向其附加其他节点,但是当我们将其插入某个位置时,则会插入其内容。
例如,下面这段代码中的 getListContent 会生成带有 <li> 列表项的片段,然后
将其插入到 <ul> 中:
请注意,在最后一行 (*) 我们附加了 DocumentFragment ,但是它和 ul “融为一
体(blends in)”了,所以最终的文档结构应该是:
DocumentFragment 很少被显式使用。如果可以改为返回一个节点数组,那为什么
还要附加到特殊类型的节点上呢?重写示例:
</div>
<script>
let div2 = div.cloneNode(true); // 克隆消息
div2.querySelector('strong').innerHTML = 'Bye there!'; // 修改克隆
div.after(div2); // 在已有的 div 后显示克隆
</script>

节点属性

nodeType

我们可以使用它来查看节点是文本节点还是元素节点。它具有一个数值型值(numeric value): 1 表示元素, 3 表示文本节点,其他一些则代表其他节点类型。只读。

nodeName/tagName

用于元素名,标签名(除了 XML 模式,都要大写)。对于非元素节点, nodeName 描 述了它是什么。只读。

alert( document.body.nodeName ); // BODY
alert( document.body.tagName ); // BODY

差别:
tagName 属性仅适用于 Element 节点。
nodeName 是为任意 Node 定义的:
对于元素,它的意义与 tagName 相同。
对于其他节点类型(text,comment 等),它拥有一个对应节点类型的字符串

innerHTML

元素的 HTML 内容。可以被修改。

<body>
<p>A paragraph</p>
<div>A div</div>
<script>
alert( document.body.innerHTML ); // 读取当前内容
document.body.innerHTML = 'The new BODY!'; // 替换它
</script>
</body>

我们可以尝试插入无效的 HTML,浏览器会修复我们的错误:

<body>
<script>
document.body.innerHTML = '<b>test'; // 忘记闭合标签
alert( document.body.innerHTML ); // <b>test</b>(被修复了)
</script>
</body>

innerHTML+= 做了以下工作:

  1. 移除旧的内容。
  2. 然后写入新的 innerHTML (新旧结合)。
    相同效果:
elem.innerHTML += "...";
// 进行写入的一种更简短的方式:
elem.innerHTML = elem.innerHTML + "..."

innerText

与innerHTNL不同,只获取文本

outerHTML

元素的完整 HTML。对 elem.outerHTML 的写入操作不会触及 elem 本身。而是在 外部上下文中将其替换为新的 HTML。

<div id="elem">Hello <b>World</b></div>
<script>
alert(elem.outerHTML); // <div id="elem">Hello <b>World</b></div>
</script>

注意:与innerHTML不同,写入outerHTML不会改变元素,而是在DOM 中替换它。

<div>Hello, world!</div>
<script>
let div = document.querySelector('div');
// 使用 <p>...</p> 替换 div.outerHTML
div.outerHTML = '<p>A new element</p>'; // (*)
// 蛤!'div' 还是原来那样!
alert(div.outerHTML); // <div>Hello, world!</div> (**)
</script>

nodeValue/data

非元素节点(文本、注释)的内容。两者几乎一样,我们通常使用 data 可以被修改。
读取文本节点和注释节点的内容的示例:

<body>
Hello
<!-- Comment -->
<script>
let text = document.body.firstChild;
alert(text.data); // Hello
let comment = text.nextSibling;
alert(comment.data); // Comment
</script>
</body>

textContent

元素内的文本:HTML 减去所有 <tags> 。写入文本会将文本放入元素内,所有特殊 字符和标签均被视为文本。可以安全地插入用户生成的文本,并防止不必要的 HTML 插入。

<div id="news">
<h1>Headline!</h1>
<p>Martians attack people!</p>
</div>
<script>
// Headline! Martians attack people!
alert(news.textContent);
</script>

假设我们有一个用户输入的任意字符串,我们希望将其显示出来。
使用 innerHTML ,我们将其“作为 HTML”插入,带有所有 HTML 标签。
使用 textContent ,我们将其“作为文本”插入,所有符号(symbol)均按字面意 义处理。

hidden

当被设置为 true 时,执行与 CSS display:none 相同的事。

<div>Both divs below are hidden</div>
<div hidden>With the attribute "hidden"</div>
<div id="elem">JavaScript assigned the property "hidden"</div>
<script>
elem.hidden = true;
</script>

操作

一.
elem.hasAttribute(name) — 检查是否存在这个特性。
elem.getAttribute(name) — 获取这个特性值。
elem.setAttribute(name, value) — 设置这个特性值。
elem.removeAttribute(name) — 移除这个特性。
elem.attributes — 所有特性的集合。

<body>
<div id="elem" about="Elephant"></div>
<script>
alert( elem.getAttribute('About') ); // (1) 'Elephant',读取
elem.setAttribute('Test', 123); // (2) 写入
alert( elem.outerHTML ); // (3) 查看特性是否在 HTML 中(在)
for (let attr of elem.attributes) { // (4) 列出所有
alert( `${attr.name} = ${attr.value}` );
}
</script>
</body>

二.

image.png

样式

一·

image.png

二.

image.png

className

className — 字符串值,可以很好地管理整个类的集合。

image.png

classList

具有 add/remove/toggle/contains 方法的对象,可以很好 地支持单个类。
方法:
elem.classList.add/remove(class) — 添加/移除类。
elem.classList.toggle(class) — 如果类不存在就添加类,存在就移除 它。
elem.classList.contains(class) — 检查给定类,返回 true/false 。

获取元素节点

getElementById

image.png

getElementsByName(name)

返回在文档范围内具有给定 name 特性的元素

getElementsByClassName(className)

返回具有给定CSS类的元素。

getElementsByTagName(tag)

查找具有给定标签的元素,并返回它们的集合。 tag 参数也可以是对于“任何标签”的星号 "*"

// 获取文档中的所有 div
let divs = document.getElementsByTagName('div');

querySelectorAll

返回元素中与给定 CSS 选择器匹配的所有元素。

<ul>
<li>The</li>
<li>test</li>
</ul>
<ul>
<li>has</li>
<li>passed</li>
</ul>
<script>
let elements = document.querySelectorAll('ul > li:last-child');
for (let elem of elements) {
alert(elem.innerHTML); // "test", "passed"
</script>

querySelector

调用会返回给定 CSS 选择器的第一个元素

matches

检查元素是否与给定的 CSS 选择器匹配。它返回 true 或 false 。

closest

元素的祖先(ancestor)是:父级,父级的父级,它的父级等。祖先们一起组成了从元 素到顶端的父级链。
查找与 CSS 选择器匹配的最近的祖先。 元素自己也会被搜索。
方法 closest 在元素中得到了提升,并检查每个父级。如果它与选择器 匹配,则停止搜索并返回该祖先。

h1>Contents</h1>
<div class="contents">
<ul class="book">
<li class="chapter">Chapter 1</li>
<li class="chapter">Chapter 1</li>
</ul>
</div>
<script>
let chapter = document.querySelector('.chapter'); // LI
alert(chapter.closest('.book')); // UL
alert(chapter.closest('.contents')); // DIV
alert(chapter.closest('h1')); // null(因为 h1 不是祖先)
</script>

注意

所有的 "getElementsBy*" 方法都会返回一个 实时的(live) 集合。这样的集合始终反映的是文档的当前状态,并且在文档发生更改时会“自动更新”。

<div>First div</div>
<script>
let divs = document.getElementsByTagName('div');
alert(divs.length); // 1
</script>
<div>Second div</div>
<script>
alert(divs.length); // 2
</script>

querySelectorAll 返回的是一个 静态的 集合。就像元素的固定数组。 如果我们使用它,那么两个脚本都会输出 1 :

<div>First div</div>
<script>
let divs = document.querySelectorAll('div');
alert(divs.length); // 1
</script>
<div>Second div</div>
<script>
alert(divs.length); // 1
</script>

获取元素尺寸

image.png

注意: image.png

获取元素的偏移量

image.png 参考点:定位父级
如果父级元素没有定位,偏移量相当于body

image.png 参考点:自身(相当于边框)

获取可视窗口的尺寸

image.png

事件

基本

image.png

事件解绑

image.png

image.png

image.png

事件类型

鼠标事件

click —— 当鼠标点击一个元素时(触摸屏设备会在点击时生成)
dbclick —— 双击执行 contextmenu —— 当鼠标右键点击一个元素时
mouseover / mouseout —— 当鼠标指针移入/离开一个元素时
mousedown / mouseup —— 当在元素上按下/释放鼠标按钮时
mousemove —— 当鼠标移动时

键盘事件

keydown 和 keyup —— 当按下和松开一个按键时

表单(form)元素事件

submit —— 当访问者提交了一个 <form> 时
focus —— 当访问者聚焦于一个元素时,例如聚焦于一个<input>

触摸事件

image.png

Document事件

DOMContentLoaded —— 当 HTML 的加载和处理均完成,DOM 被完全构建完成 时

CSS 事件

transitionend —— 当一个 CSS 动画完成时

事件对象

基本介绍

image.png

image.png

鼠标事件

  1. 相对于窗口的坐标: clientX 和 clientY
  2. 相对于文档的坐标: pageX 和 pageY
  3. 相对于触发元素的坐标:offsetX 和 offsetY
    例如,如果我们有一个大小为 500x500 的窗口,并且鼠标在左上角,那么 clientX 和 clientY 均为 0 ,无论页面如何滚动。
    如果鼠标位于中间,那么 clientX 和 clientY 均为 250 。这与它在文档中的位置 无关。在这方面,它们类似于 position:fixed 。

阻止事件传播

image.png

阻止默认行为

image.png

事件委托

image.png