关于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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理