js DOM

《JavaScript高级程序设计》读书笔记

 文档对象模型(DOM,Document Object Model)是HTML 和 XML 文档的编程接口。DOM 表示由多层节点构成的文档。

节点层级

HTML 中的每段标记都可以表示为这个树形结构的一个节点。元素节点表示 HTML 元素,属性节点表示属性,文档类型节点表示文档类型,注释节点表示注释。DOM 中总共有12种节点类型,这些类型都继承一种基本类型。

Node 类型

NameValue
ELEMENT_NODE1
ATTRIBUTE_NODE2
TEXT_NODE3
CDATA_SECTION_NODE4
PROCESSING_INSTRUCTION_NODE7
COMMENT_NODE8
DOCUMENT_NODE9
DOCUMENT_TYPE_NODE10
DOCUMENT_FRAGMENT_NODE11

1. nodeName 与 nodeValue

if(someNode.nodeType == 1) {
    value = someNode.nodeName;
}

2. 节点关系

每个节点都有一个childNodes 属性,其中包含一个NodeList 的实例。NodeList 是一个类数组对象,用于存储可以按位置存却的有序节点,是实时的活动对象。

  • parentNode 父节点
  • childNodes
  • previousSibling
  • nextSibling
  • firstChild 第一个节点
  • lastChild 最后一个节点
  • hasChildNodes() 如果返回true,则说明节点有一个或多个字节点
  • ownerDocument 指向代表整个文档的文档节点的指针

3. 操作节点

  • appendChild() 用于在childNodes 列表末尾添加节点。方法返回新添加的节点
  • insertBefore() 接收两个参数:要插入的节点和参照节点。要插入的节点会变成参照节点前一个同胞节点
  • replaceChild() 接收两个参数:要插入的节点和要替换的节点。要替换的节点会被返回并从文档树中完全移除,要插入的节点会取而代之
  • removeChild() 移除节点。方法返回移除节点。

4. 其他方法

  • cloneNode() 接收一个布尔值参数,表示是否深复制。true:会进行深复制,即复制节点及其整个子DOM 树。false:只会复制调用该方法的节点。
  • normalize() 将当前节点和它的后代节点”规范化“。如果发现空文本节点,则将其删除;如果两个同胞节点是相邻的,则将其合并为一个文本节点。

Document 类型

Document 类型是 JavaScript 中表示文档节点的类型。在浏览器中,文档对象document 是 HTMLDocument 的实例,表示整个HTML 页面。document 是 window对象的属性。

特征:

  • nodeType 等于 9
  • nodeName 值为 "#document"
  • nodeValue 值为null
  • parentNode 值为null
  • ownerDocument 值为null
  • 子节点可以是DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或Comment 类型

1. 文档字节点

  • document.documentElement 取得对html 的引用
  • document.body
  • document.doctype 取得对<!doctype> 的引用

2. 文档信息

// 文档标题
document.title
// 完整的URL
document.URL
// 域名
document.domain
// 链接到当前页面的那个页面的URL
document.referrer

3. 定位元素

  • getElementById() 接收一个参数,即要获取元素的ID
  • getElementByTagName() 接收一个参数,即要获取元素的标签名
  • getElementByName() 返回具有给定name 属性的所有元素

4. 特殊集合

  • document.anchors
  • document.applets
  • document.forms
  • document.images
  • document.links

5. 文档写入

  • write()
  • writeln()
  • open()
  • close()

Element 类型

表示XML 或 HTML 元素。

特征:

  • nodeType 等于1
  • nodeName 值为元素的标签名
  • nodeValue 值为null
  • parentNode 值为Document 或 Element 对象
  • 子节点可以是 Element、Text、Comment、ProcessingInstruction、CDATASection、EntityReference类型

可以通过 nodeName 或 tagName 属性来获取元素的标签名。

1. HTML 元素

标准属性:

  • id
  • title
  • lang
  • dir
  • className

2. 属性操作

  • getAttribute()
  • setAttribute()
  • removeAttribute()

3. attributes 属性

  • getNamedItem(name)
  • removeNamedItem(name)
  • setNamedItem(node)
  • item(pos)

4. 创建元素

document.createElement()

Text 类型

字面量解释的存文本或转义后的HTML 字符

特征:

  • nodeType 等于3
  • nodeName 值为 “#text”
  • nodeValue 值为节点中包含的文本
  • parentNode 值为Element 对象
  • 不支持子节点

操作文本的方法:

  • appendData(text) 向节点末尾添加文本text
  • deleteData(offset, count) 从位置offset 开始删除 count 个字符
  • insertData(offset, text) 在位置offset 插入 text
  • replaceDate(offset, count, text) 用text 替换从位置offset 到 offset + count 的文本
  • splitText(offset) 在位置offset 将当前文本节点拆分为两个文本节点
  • substringData(offset, count) 提取从位置offset 到 offset + count 的文本

1. 创建文本节点

document.createTextNode()

2. 规范化文本节点

normalize()

let element = document.createElement("div");
element.className = "message";

let textNode = document.createTextNode("Hello!");
element.appendChild(textNode);

let anotherTextNode = document.createTextNode("Word");
element.appendChild(anotherTextNode);

alert(element.childNodes.length);    // 2

element.normalize();
alert(element.childNodes.length);    // 1

Comment 类型

注释

特征:

  • nodeType 等于8
  • nodeName 值为 “#comment”
  • nodeValue 值为注释的内容
  • parentNode 值为 Document 或 Element 对象
  • 不支持子节点

Comment 类型与 Text 类型继承同一个基类(CharacterData),因此拥有除 splitText() 之外Text 节点所有的字符串操作方法。

创建注释节点:document.createComment()

CDATASection 类型

XML 中特有的CDATA 区块(只在XML 文档中有效),继承 Text 类型

特征:

  • nodeType 等于4
  • nodeName 值为"#cdata-section"
  • nodeValue 值为CDATA 区块的内容
  • parentNode 值为Document 或 Element 对象
  • 不支持子节点

创建:document.createCDataSection()

DocumentType 类型

文档的文档类型信息

特征:

  • nodeType 等于10
  • nodeName 值为文档类型的名称
  • nodeValue 值为null
  • parentNode 值为 Document 对象
  • 不支持子节点

该对象保存在 document.dotype 属性中。具有3个属性:name、entities、notations

DocumentFragment 类型

文档片,存储由节点(nodes)组成的文档结构,它的变化不会触发DOM树的重新渲染

特征:

  • nodeType 等于11
  • nodeName 值为"#document-fragment"
  • nodeValue 值为null
  • parentNode 值为null
  • 子节点可以是 Element、ProcessingInstruction、Comment、Text、CDATASection 或 EntityReference
let fragment = document.createDocumentFragment();
let ul = document.getElementById("myList");
for(let i = 0;i < 3;++i) {
    let li = document.createElement("li");
    li.appendChild(document.createTextNode(`Item ${i + 1}`));
    fragment.appendChild(li);
}
ul.appendChild(fragment);

Attr 类型

元素数据

特征:

  • nodeType 等于2
  • nodeName 值为属性名
  • nodeValue 值为属性值
  • parentNode 值为null
  • 在 HTML 中不支持子节点
  • 在 XML 中子节点可以是Text 或 EntityReference

该对象上有3个属性:name、value、specified

let attr = document.createAttribute("align");
attr.value = "left";
element.setAttributeNode(attr);

DOM 编程

动态脚本

引入外部文件和直接插入源代码

let script = document.createElement("script");
script.src = "foo.js";
document.body.appendChild(script);
// 另一种
script.appendChild(document.createTextNode("function sayHi(){alert('hi');}));

动态样式

let link = document.createElement("link");
link.ref = "stylesheet";
link.type = "text/css";
link.href = "style.css";
let head = ducument.getElementsByTagName("head")[0];
head.appendChild(link);

MutationObserver 接口

提供了监视对 DOM 树所做更改的能力

基本用法

1. observe(target[, options]) 方法

配置 MutationObserver 在 DOM 更改匹配给定选项时,通过其回调函数开始接收通知。接收两个参数:要观察其变化的DOM 节点,一个 MutationObserverInit 对象。

options:

属性说明
subtree布尔值,表示除了目标节点,是否观察目标节点的子树(后代)
如果是 false,则只观察目标节点的变化;如果是 true,则观察目标节点及其整个子树
attributes布尔值,表示是否观察目标节点的属性变化
默认为 false
attributeFilter字符串数组,表示要观察哪些属性的变化
把这个值设置为 true 也会将 attributes 的值转换为 true
默认为观察所有属性
attributeOldValue布尔值,表示 MutationRecord 是否记录变化之前的属性值
把这个值设置为 true 也会将 attributes 的值转换为 true
默认为 false
characterData布尔值,表示修改字符数据是否触发变化事件
默认为 false
characterDataOldValue布尔值,表示 MutationRecord 是否记录变化之前的字符数据
把这个值设置为 true 也会将 characterData 的值转换为 true
默认为 false
childList布尔值,表示修改目标节点的子节点是否触发变化事件
默认为 false

例:

如下<body> 元素上任何属性发生变化都会被这个MutationObserver 实例发现,然后执行异步注册的回调函数。配置了元素后代的修改或其他属性修改都不会触发回调进入任务队列。

let observer = new MutationObserver(() => console.log('body 修改监听'));
observer.observe(document.body, { attributes: true});
document.body.className = 'foo';
// body 修改监听

2. 回调

回调函数接收两个参数:

  • MutationRecord 实例的数组。包含的信息包括一个发生了什么的数组
  • 观察变化的 MutationObserver 的实例

MutationRecord 的实例属性

属性说明
target被修改影响的目标节点
type字符串,表示变化的类型:attributes、characterData、childList
oldValue

如果在 MutationObserverInit 对象中启用( attributeOldValue 或 characterData OldValue
为 true), "attributes"或"characterData"的变化事件会设置这个属性为被替代的值
"childList"类型的变化始终将这个属性设置为 null

attributeName对于"attributes"类型的变化,这里保存被修改属性的名字
其他变化事件会将这个属性设置为 null
attributeNamespace对于使用了命名空间的"attributes"类型的变化,这里保存被修改属性的名字
其他变化事件会将这个属性设置为 null
addedNodes对于"childList"类型的变化,返回包含变化中添加节点的 NodeList
默认为空 NodeList
removedNodes对于"childList"类型的变化,返回包含变化中删除节点的 NodeList
默认为空 NodeList
previousSibling对于"childList"类型的变化,返回变化节点的前一个同胞 Node
默认为 null
nextSibling对于"childList"类型的变化,返回变化节点的后一个同胞 Node
默认为 null

3. disconnect() 方法

告诉观察者停止观察变动。 可以通过调用其 observe() 方法来重用观察者。

observer.disconnect();

4. taskRecords() 方法

返回已检测到但尚未由观察者的回调函数处理的所有匹配 DOM 更改的列表,使变更队列保持为空。 此方法最常见的使用场景是在断开观察者之前立即获取所有未处理的更改记录,以便在停止观察者时可以处理任何未处理的更改。

5. 复用 MutationsObserver

let observer = new MutationObserver((mutationRecords) => console.log(mutationRecords.map(x => x.target)));
let childA = document.createElement("div");
let childB = document.createElement("span");
document.body.appendChild(childA);
document.body.appendChild(childB);

observer.observe(childA, {attributes: true});
observer.observe(childB, {attributes: true});

childA.setAttribute('foo', 'bar');
childB.setAttribute('foo', 'bar');
// [div, span]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞天巨兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值