乐趣区

关于javascript:读书笔记第四版JavaScript高级程序设计第十四章

前言

单纯的笔记,没别的

节点的类型

节点类型

一共有 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

  1. write 如果产生在 oload 之后执行,write 办法会重写整个页面。
  2. 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
退出移动版