共计 8423 个字符,预计需要花费 22 分钟才能阅读完成。
前言
单纯的笔记,没别的
节点的类型
节点类型
一共有 12 种节点的类型,节点类型通过 nodeType 获取,应用数字 1~12 示意
- nodeType,节点的类型
- nodeName,取决于节点的类型,对于 Element 类型的元素,nodeName 等于标签名
- nodeValue,取决于节点的类型,对于 Element 类型的元素,nodeValue 等于 null
节点关系
- childNodes 属性,蕴含 NodeList 类数组对象。NodeList 能够间接应用中括号 NodeList[0], NodeList.item(1), 拜访其中的元素。Array.from 转成数组对象
- parentNode 属性,指向父节点
- previousSibling,前一个兄弟节点,第一个的前一个是 null,
- nextSibling,后一个兄弟节点, 最初一个的后一个是 null,
- firstChild,第一个子节点
- lastChild,最初一个子节点
- hasChildNodes(), 如果存在子节点返回 true
操纵节点
- parentNode.appendChild(), 在 childNodes 列表开端增加元素,并返回新的元素。如果是已有元素,则会挪动当初的节点。
- parentNode.iertBefore(插入节点,参考节点),如果参考节点是 null,会插入到最初一个节点。如果参考节点是 firstChild,则参入到第一个节点。
- parentNode.replaceChild(替换节点,参考节点)
- parentNode.removeChild(删除的节点)
- cloneNode(boolean), boolean 传 false 只会复制以后的节点,传 true 会复制以后节点极其子节点,cloneNode 不会复制由 js 增加的属性,比方事件处理程序。
- normalize,规范化文本节点
Document 类型
文档对象 document 是 HTMLDocument 的实例(HTMLDocument 继承 Document),示意整个 HTML 页面。document 是 window 对象的属性,因而是一个全局对象。Document 的 nodeType 类型等于 9
文档子节点
- document.documentElement,返回 html 元素
- document.childNodes[0], 返回 html 元素
- body 属性,返回 body 元素
- doctype 属性, 返回 <!DOCTYPE html>
- title,蕴含 <title> 标签的文本
- URL, 以后页面残缺的 url
- domain,以后页面的域名, 能够批改,然而只能批改一次
- referrer,页面的起源
???? document.domain, 是能够批改的,然而批改有限度,比方 www.baidu.com, 能够批改为 image.baidu.com。
???? 当一个页面嵌套一个 iframe 时,能够批改 iframe 的 domain 属性,两个文档的 domain 属性一样时,能够共享 javascript 对象。
定位元素
- getElementById
-
getElementsByTagName,返回 HTMLCollection 类数组对象
- HTMLCollection 对象的 namedItem 办法,能够依据指定节点 name,获取元素
- document.getElementsByTagName(‘*’), 会返回所有元素
- getElementsByName,获取指定 name 的元素
- document.images,获取所有的图片元素
- document.links,获取所有蕴含 href 属性的,a 标签
- document.forms,获取所有的 form 元素
const images = document.getElementsByTagName('img')
// 获取 name 属性为 t1 的图片
images.namedItem('t1')
文档写入
- write,写入文本
- writeln,写入文本并换行
- open, 关上网页
- close, 敞开网页
write
- write 如果产生在 oload 之后执行,write 办法会重写整个页面。
- write 如果产生在 oload 之后前执行, write 办法会写在以后 script 之后的地位。write 在写入
script
标签的时候,
Element 类型
Element 类型的 nodeType 等于 1,nodeName 等于标签名,nodeValue 等于 null.
nodeName 和 tagName 返回同样的值,然而 tagName 通常返回标签名的大写
HTML
所有 HTML 元素都是 HTMLElement 类型,HTMLElement 类型继承自 Element 类型,并减少了一些本人的属性。
罕用的属性:
- id
- title,额定信息
- dir, 书写方向
- className
属性办法
- getAttribute,获取属性,属性名不辨别大小写,ID 等同于 id。
- setAttribute(key, value),设置属性, 属性名会主动标准为小写
- removeAttribute,删除属性,不仅仅是删除 value。会删除 key 和 value
attributes 属性
attributes 属性蕴含一个 NamedNodeMap 实例,元素的每一个属性都保留在 NamedNodeMap 实例中。
- getNamedItem(name),返回 NamedNodeMap 实例中,属性等于 name 的节点
- removeNamedItem(name),删除属性等于 name 的节点
- setNamedItem(node),设置属性节点
// id1 和 id2 是等同的
const id1 = element.attributes.getNamedItem("id").nodeValue;
const id2 = element.attributes["id"].nodeValue;
// 删除属性
element.attributes.removeNamedItem("id")
// 设置属性
const node = document.createAttribute("class");
node.value = "democlass";
element.attributes.setNamedItem(node);
// 或者能够间接批改属性值
element.attributes["id"].nodeValue = "someOtherId";
创立元素
- document.createElement(),创立元素
Text 类型
nodeType 等于 3,nodeValue 等于文本内容,nodeName 值等于 #text,不反对子节点。parentNode 的是 Element 对象。获得文本节点的援用后,能够间接通过 nodeValue 批改
const textNode = document.getElementsByClassName('color_h1')[0]
textNode.firstChild.nodeValue = 'Hello'
// 或者批改 data 属性,成果和 nodeValue 一样
textNode.firstChild.data = 'Hello'
创立文本节点
- document.createTextNode()
let element = document.createElement("div");
element.className = "message";
// 创立文本节点,并插入到 element 中
let textNode1 = document.createTextNode("Hello");
element.appendChild(textNode1);
// 能够插入多个文本节点
let textNode2 = document.createTextNode("World!");
element.appendChild(textNode2);
document.body.appendChild(element);
规范化文本节点
在蕴含多个文本节点的元素上调用 normalize 办法,会将文本节点合并为一个文本节点
let element = document.createElement("div");
element.className = "message";
// 创立文本节点,并插入到 element 中
let textNode1 = document.createTextNode("Hello");
element.appendChild(textNode1);
// 能够插入多个文本节点
let textNode2 = document.createTextNode("World!");
element.appendChild(textNode2);
// 将会合并文本节点
element.normalize()
Comment 类型
正文节点类型,nodeType 等于 8,nodeValue 是正文的内容,nodeName 值等于 #comment”,parentNode 是 Document 或者 Element,不反对子节点
// <div id="test"><!-- 正文 --></div>
let element = document.getElementById("test");
// 正文节点
let comment = div.firstChild;
// 正文节点的内容
console.log(comment.data)
console.log(comment.nodeValue)
创立正文节点
- document.createComment()
CDATASection 类型
nodeType 等于 4, 其余内容略过……
DocumentType 类型
nodeType 等于 10,不反对动态创建,parentNode 等于 Docuemtn 对象,能够应用 document.doctype 获取 DocumentType 对象。
- name,文档类型的名称,
<!DOCTYPE
前面的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// html
console.log(document.doctype.name)
</script>
</body>
</html>
DocumentFragment 类型
文档片段, nodeType 等于 11,DocumentFragment 能够了解为一个仓库,DocumentFragment 里存储着所有要增加到文档里的节点
创立文档片段
- document.createDocumentFragment
应用
// 如果不应用文档片段,浏览器会渲染 3 次
let ul = document.getElementById("myList");
for (let i = 0; i < 3; ++i) {let li = document.createElement("li");
li.appendChild(document.createTextNode(`Item ${i + 1}`));
ul.appendChild(fragment);
}
// 应用文档片段后,浏览器只会渲染一次
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 类型
Attr 节点存在在元素的 attributes 属性上,nodeType 等于 2,nodeName 等于属性名,nodeValue 等于属性值,Attr 类型尽管是节点,但不是 DOM 树的一部分
// attr 节点的 name 为 align
let attr = document.createAttribute("align");
// attr 节点的 value 为 left
attr.value = "left";
// 为元素设置属性
element.setAttributeNode(attr);
DOM 编程
动静脚本
对于动静插入的内联 script 脚本,如果是应用 innerHTML 插入的 script,不会执行。只能通过 appendChild,等 DOM 的 API 插入节点。
const script = document.createElement("script");
script.type = "text/javascript";
script.appendChild(document.createTextNode(code));
// 能够执行
document.body.appendChild(script)
// script 无奈执行
document.body.innerHTML = script
动静款式
function loadStyleString(css){let style = document.createElement("style");
style.type = "text/css";
style.appendChild(document.createTextNode(css));
let head = document.getElementsByTagName("head")[0];
head.appendChild(style);
}
NodeList
NodeList 和 HTMLCollection 很类似,然而 HTMLCollection 对象有额定的 namedItem 办法,能够通过元素的 name 获取援用
MutationObserver
MutationObserver,能够察看整个文档,或者 DOM 的一部分,或者某个元素。当发生变化时,会异步的触发 callback
根本应用
// mo 不会关联任何 DOM 对象,而是须要应用 observer
// 关联具体的 dom 对象曾经须要察看的属性
const mo = new MutationObserver(() => {console.log('dom change')
})
// 察看 document.body 元素,属性的变动。当 body 的属性发生变化,就会触发 MutationObserver 中的 callback
// 然而 document.body 子代的变动,或者 docuemnt.body 其余内容的变动,不会触发 callback,
mo.observer(document.body, {attributes: true})
MutationRecord 数组
MutationRecord 数组记录了一组信息,认为回调的触发可能是多个操作引起的。每个信息里蕴含了产生了那些变动,影响到那些元素等。
const div = document.getElementById('id1');
const mo = new MutationObserver((MRecord) => {
// 打印后果如下
console.log(MRecord);
});
mo.observe(div, {attributes: true,});
div.dataset.name = 'World!';
屡次的批改 MutationRecord 数组中会有多个内容
const div = document.getElementById('id1');
const mo = new MutationObserver((MRecord) => {console.log(MRecord);
});
mo.observe(div, {attributes: true,});
div.dataset.name = 'World!';
div.dataset.name = 'Hello World!';
callback
callback 的第一个参数是 MutationRecord 的数组,第二个参数是 MutationObserver 的实例
disconnect 办法
调用 disconnect 办法,会进行监听回调。
// 进行监听回调
mo.disconnect()
MutationObserver 复用
屡次调用 observe 办法,能够察看多个节点。
const div1 = document.getElementById('id1');
const div2 = document.getElementById('id2');
const mo = new MutationObserver((MRecord) => {console.log(MRecord);
});
mo.observe(div1, {attributes: true,});
mo.observe(div2, {attributes: true,});
div1.dataset.name = '1';
div2.dataset.name = '2';
MutationObserver 重用
调用 disconnect 不会终止 MutationObserver 实例的生命,咱们能够从新调用 observe,并持续应用它
const div1 = document.getElementById('id1');
const div2 = document.getElementById('id2');
const mo = new MutationObserver((MRecord) => {
// MRecord 数组只有一个内容
console.log(MRecord);
});
mo.observe(div1, {attributes: true,});
div1.dataset.name = '1';
mo.disconnect();
mo.observe(div2, {attributes: true,});
div2.dataset.name = '2';
MutationObserverInit 与察看范畴
MutationObserver 能够察看属性的变动,子节点的变动,和文本的变动
- subtree,boolean,是否察看子代
- attributes, boolean,是否察看属性
- attributeFilter,string[], 具体察看那些属性的变动
- attributeOldValue,boolean, 在 MutationRecord 数组中是否记录之前的属性值。
- characterData,boolean,是否察看批改字符数据的变动(文本节点,正文节点)
- characterDataOldValue, boolean, 在 MutationRecord 数组中是否记录之前的字符值。
- childList,boolean, 批改子节点是否触发察看
subtree, 设置为 true,察看整个子数。如果将后辈移除子树后,脱离了原来的子树后,对其批改,仍然会触发变动。
childList, 设置为 true,只察看一级子树
异步回调和记录队列
每一次的变动信息会记录在 MutationRecord 实例中,而后增加到记录队列中,这个队列是每个 MutationObserver 实例惟一的。每一次 MutationRecord 被增加到队列中之后,如果以后微工作队列的长度为 0,才会触发之前注册的回调。
takeRecords
清空队列,并返回队列中的内容。同时会进行回调监听
// 不会触发 console
let observer = new MutationObserver((mutationRecords) => console.log(mutationRecords));
observer.observe(document.body, { attributes: true});
document.body.className = 'foo';
document.body.className = 'bar';
document.body.className = 'baz';
// [MutationRecord, MutationRecord, MutationRecord]
console.log(observer.takeRecords());
// []
console.log(observer.takeRecords());
性能、内存与垃圾回收
MutationObserver 对指标 DOM 是弱援用。如果指标节点被垃圾回收,MutationObserver 不会妨碍回收。
指标节点对 MutationObserver 是强援用,如果指标节点被回收,MutationObserver 也会被回收。
MutationRecord 实例会妨碍节点被垃圾回收。能够提取出 MutationRecord 有用的信息,保留到新对象中。
参考
- Mutation Observers—subtree