DOM

DOM

1. 节点层级

document节点表示每个文档的根节点,根节点的唯一子节点是<html>元素,称为文档元素(documentElement)。

1.1 Node类型

每个节点都有nodeType属性,表示该节点的类型。节点类型由定义在Node类型上的12个数值常量

if (someNode.nodeType == Node.ELEMENT_NODE){
	alert("Node is an element.");
}
  1. nodeName、nodeValue

    if (someNode.nodeType == 1){
    	value = someNode.nodeName; // 会显示元素的标签名
    }
    // 元素节点的nodeValue属性为null
    

  2. 节点关系

    每个节点都有一个childNodes属性,其中包含一个NodeList的实例。NodeList会根据DOM结构实时更新。

    let firstChild = someNode.childNodes[0];
    let secondChild = someNode.childNodes.item(1); //支持item方法
    let count = someNode.childNodes.length;
    
    //转换为数组
    let arrayOfNodes = Array.prototype.slice.call(someNode.childNodes, 0);
    //或
    let arrayOfNodes = Array.from(someNode.childNodes);
    

    每个节点都有一个parentNode属性,指向其DOM树中的父元素。使用previousSibling和 nextSibling可以在胞亲之间导航。

    父节点和它的第一个及最后一个子节点也有专门属性: firstChildlastChild分别指向childNodes中的 第一个和最后一个子节点。

    最后还有一个所有节点都共享的关系。ownerDocument 属性是一个指向代表整个文档的文档节点的指针。


  3. 操纵节点

    appendChild() 用于在childNodes列表末尾添加节点,方法返回新添加的节点。

    如果节点时已经存在节点,则会移动节点。一个节点不会在文档中同时出现在两个或更多个地方。

    insertBefore() 可以将节点插入到特定位置:

    // 第二个参数传入null时与appendChild()相同
    returnedNode = someNode.insertBefore(newNode, null);
    alert(newNode == someNode.lastChild); //true
    // 作为新的第一个子节点插入
    returnedNode = 
    someNode.insertBefore(newNode, someNode.firstChild);
    

    replaceChild() 接收两个参数:要插入的节点和要替换的节点

    // 替换第一个子节点
    let returnedNode =
    someNode.replaceChild(newNode, someNode.firstChild);
    

    removeChild() 用于移除节点

    // 删除第一个子节点
    let formerFirstChild = someNode.removeChild(someNode.firstChild);
    

  4. 其他方法

    cloneNode() 复制节点,如果传入true则还会复制内部子节点(不会复制事件处理程序)

    let deepList = myList.cloneNode(true);
    alert(deepList.childNodes.length);
    

    normalize() 用于处理文本节点,后面讨论。


1.2 Document类型

属性 描述
document.documentElement 始终指向HTML页面中的<html>元素
document.body 直接指向<body>元素
document.doctype 指向<!doctype>标签
document.title 可以修改标题栏,但不会改变<title>标签中的内容
document.referrer 获取链接到当前页面的那个页面的URL
  1. 定位元素

    方法 描述
    getElementById() 接收元素id,如果找到返回元素,没找到返回null,多个则返回第一个
    getElementsByTagName() 接收一个参数,要获取元素的标签名,返回包含零个或多个元素的NodeList。
    getElementsByName() 根据name属性返回元素NodeList 常用于表单
    // <img src="myimage.gif" name="myImage">
    let images = document.getElementsByTagName("img");
    let myImage = images["myImage"]; //通过name获取
    

  2. 特殊集合

    document.forms:所有表单

    document.images:所有图片

    document.links:所有链接


1.3 Element类型

可以通过nodeName或tagName来获取标签名(大写)

if (element.tagName.toLowerCase() == "div"){ 
	//推荐,适用于所有文档
}
  1. HTML元素

    有5个标准属性,id,dir(文字方向),lang,title(鼠标放置后显示),className(相当于class,class为关键字不可以使用)

    <div id="myDiv" class="bd" title="Bodytext" lang="en" dir="ltr"></div>
    

    这些都有对应的属性值可以修改

    let div = document.getElementById("myDiv");
    alert(div.id); // "myDiv"
    alert(div.className); // "bd"
    div.id = "someOtherId";
    div.className = "ft";
    

  2. 取得属性

    getAttribute()、setAttribute()和 removeAttribute()。

    let div = document.getElementById("myDiv");
    alert(div.getAttribute("id")); //"myDiv"
    alert(div.getAttribute("class")); //"bd"
    // 这里要注意class而不是className要填真实名称
    

    根据html5 的要求自定义属性要以data-开头

    除了五个标准属性还有其他公认(非自定义)属性也是DOM对象属性(如align)

    div.align='left';
    

    getAttribute()和DOM属性访问的两个差异

    1. style属性

      getAttribute()访问style属性时,返回的是CSS字符串。

      通过DOM对象的属性访问时,style属性返回的是一个(CSSStyleDeclaration)对象。DOM对象的style属性用于以编程方式读写元素样式,因此不会直接映射为元素中style属性的字符串值。

    2. 所有事件属性

      当在元素上使用事件属性时(比如 onclick),属性的值是一段JavaScript代码。

      使用 getAttribute()访问事件属性,则返回的是字符串形式的源代码,(标签上未设置则为null)

      通过DOM对象的属性访问事件属性时返回的则是一个JavaScript函数(未指定该属性则返回 null)


  3. 设置属性

    setAttribute() 可以设置html属性和自定义属性

    也可以通过DOM属性设置元素属性:

    div.id = "someOtherId";
    // DOM对象上的自定义属性,不会成为元素的属性
    div.mycolor = "red";
    alert(div.getAttribute("mycolor")); //null(IE除外)
    

  4. 创建元素

    document.createElement()方法创建新元素。这个方法接收一个参数,即要创建元素的标签名。

1.4 Text类型

Text节点中包含的文本可以通过nodeValue、data、textContext属性访问

// 输出为"Some &lt;strong&gt;other&lt;/strong&gt; message"
div.firstChild.nodeValue = "Some<strong>other</strong> message";
//HTML代码,即小于号、大于号或引号会被转义
  1. 创建节点

    document.createTextNode()

    let textNode = document.createTextNode("<strong>Hello</strong> world!");
    
  2. 规范化

    normalize() 在父节点上调用可以合并相邻全部的文本节点


2. MutationObserver接口

使用MutationObserver可以观察整个文档、DOM树的一部分,或某个元素。此外还可以观察元素属性、子节点、文本,或者前三者任意组合的变化。

2.1 基本用法

初始化并传入一个回调函数:

let observer = new MutationObserver(() => console.log('DOM was mutated!'));
  1. observe() 方法

    MutationObserver实例不会关联DOM的任何部分。要把这个observer与DOM关联起来,需要使用observe()方法。这个方法接收两个必需的参数:要观察其变化的DOM节点,以及一个MutationObserverInit对象。

    MutationObserverInit对象用于控制观察哪些方面的变化,是一个键/值对形式配置选项的字典。

    例如:观察<body>元素上的属性变化

    let observer = new MutationObserver(() => 
                         console.log('<body> attributes changed'));
    observer.observe(document.body, { attributes: true });
    
    document.body.className = 'foo';
    console.log('Changed body class');
    // Changed body class
    // <body> attributes changed
    //异步触发回调函数
    

  2. 回调与MutationRecord

    回调函数会接收一个MutationRecord对象,记录变化信息

    let observer = new MutationObserver((mutationRecords) =>
    									console.log(mutationRecords));
    

  3. disconnect()提前终止回调

    会断开与DOM之间的监视,未调用的回调不会执行

    document.body.className = 'foo';
    observer.disconnect();
    document.body.className = 'bar';
    //(没有日志输出)
    

    因为回调是异步的所以所有回调都会取消

    document.body.className = 'foo';
    setTimeout(() => { 
        observer.disconnect();
    	document.body.className = 'bar';
    }, 0);
    // <body> attributes changed
    // 这样可以执行部分
    

    4.复用MutationObserver

    // 观察两个子节点
    observer.observe(childA, { attributes: true });
    observer.observe(childB, { attributes: true });
    // 修改两个子节点的属性
    childA.setAttribute('foo', 'bar');
    childB.setAttribute('foo', 'bar');
    // [<div>, <span>]
    

    5.重用MutationObserver

    调用disconnect()并不会结束MutationObserver的生命。重新observe()绑定可以继续使用


2.2 观察范围

设置 描述
attributes: true 属性变化
attributeFilter: ['属性1','属性2'] 指定观察的属性
attributeOldValue: true 记录原属性值,保存在oldValue中
characterData: true 观察文本节点变化
characterDataOldValue: true 记录原属字符数据
childList: true 观察目标节点子节点的添加和移除
subtree: true 所有后代节点
posted @ 2021-07-22 13:15  王子饼干  阅读(113)  评论(0编辑  收藏  举报