重学JS—第十章DOM

163 阅读7分钟

0 DOM级别简介

0.1 DOM0级事件

0级DOM分为两种

  1. 行内事件:在标签中写事件
  2. 元素.on事件名=函数
1.行内 <**input** type=**"button"** id=**"btn"** value=**"****按钮****"** onclick=**"**alert(**'****你好****'**)**"**>
2.元素.on事件名=函数 document.getElementById(**"btn"**).onclick = function () { alert('你好**!**'); }

0.2 DOM1级问题

为什么没有1级DOM?
DOM级别1于1998年10月1日成为W3C推荐标准。1级DOM标准中并没有定义事件相关的内容,所以没有所谓的1级DOM事件模型。在2级DOM中除了定义了一些DOM相关的操作之外还定义了一个事件模型 ,这个标准下的事件模型就是我们所说的2级DOM事件模型

0.3 DOM2级事件

只有一个:监听方法,有两个方法用来添加和移除事件处理程序:addEventListener()和removeEventListener()。
它们都有三个参数:

第一个参数是事件名(如click);

第二个参数是事件处理程序函数;

第三个参数如果是true则表示在捕获阶段调用,为false表示在冒泡阶段调

addEventListener():可以为元素添加多个事件处理程序,触发时会按照添加顺序依次调用。

removeEventListener():不能移除匿名添加的函数。

1 节点(Node类型)

DOM1级定义了一个node接口,该接口将由DOM中的所有节点类型实现。这个Node接口在JS中是作为Node类型实现的

节点类型由在Node类型中定义的下列12个数值常量来表示,任何节点类型必为其一:

  • NODE.ELEMENT_NODE(1);
  • NODE.ATTRIBUTE_NODE(2);
  • NODE.TEXT_NODE(3);
  • NODE.CDATA_SECTION_NODE(4);
  • NODE.ENTITY_REFERENCE_NODE(5);
  • NODE.ENTITY_NODE(6);
  • NODE.PROCESSING_INSTRUCTION_NODE(7);
  • NODE.COMMENT_NODE(8);
  • NODEDOCUMENT_NODE(9);
  • NODE.DOCUMENT_TYPE_NODE(10);
  • NODE.DOCUMENT_FRAGMENT_NODE(11);
  • NODE.NOTATION_NODE(12);

1.1 nodeName和nodeValue属性

对于元素节点,nodeName中保存的始终都是元素的标签名,而nodeValue的值则始终未null

1.2 节点关系

**每个节点都有一个childNodes属性,其中保存着一个NodeList对象。NodeList是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。**请注意,虽然可以通过方括号语法来访问NodeList的值,而且这个对象也有length属性,但它并不是Array的实例。DOM结构的变化能够自动反映在NodeList对象中。

var firstChild = someNode.childNodes[0];
var secondChild = someNode.item(1);
var count = someNode.childNodes.length;

是否含有子节点:hasChildNodes()

转换为数组

var arrayOfNodes = Array.prototype.slice.call(NodeList, 0);

function convertToArray(nodes) {
    var array = null;
    try {
        array = Array.prototype.slice.call(nodes, 0);
    } catch(ex) {
        array = new Array();
        for(var i = 0, len = nodes.length; i < len; i++) {
            array.push(i);
        }
    }
    return array;
}

  • 每个节点都有一个parentNode属性,该属性指向文档树中的父节点
  • 通过使用列表中每个节点的previousSibling和nextSibling属性,可以访问同一列表中的其他节点。
  • 父节点的firstChild和lastChild属性分别指向其childNodes列表中的第一个和最后一个节点。

ownerDocument,该属性指向整个文档根节点(nodeType=9)

1.3 操作节点

appendChild()  结果返回新增节点,可向节点的子节点列表的末尾添加新的子节点。

insertBefore() 指定位置插入节点,可在已有的子节点前插入一个新的子节点。

下面俩方法移除的节点依然归文档所有,只不过没有了自己的位置

replaceChild()

removeChild()

 1.4 其他方法

cloneNode() 

   参数为true是深复制,false是浅复制

normalize()

2 节点(Document类型)

HTMLDocument类型继承于Document类型

浏览器中,

  1. document对象,是HTMLDocument的一个实例
  2. 表示整个HTML页面
  3. 是window对象的一个属性,可以作为全局对象访问

特点:

  1. nodeType 9
  2. nodeName #document
  3. nodeValue parentValue ownerDocument 都是 null

2.1 document对象的子节点

Document节点的子节点可以有四种:

  1. DocumentType(文档类型, )

  2. Element(元素,)

  3. ProcessingInstruction(XML中的DOM)

  4. Comment(注释,)

获取document的子节点

doctype属性(注意:不同浏览器兼容不一致)

document.doctype  // <!DOCTYPE html>

documentElement属性(获取元素)

body属性(获取元素)

childNodes属性

2.2 document对象的文档信息

title属性

URL属性(包含页面完整的url)

domain属性("juejin.im")

  同源跨域的解决

  松散到紧绷domain设置的报错

referrer属性(保存着链接到当前页面的那个页面的URL)

2.3 document对象查找元素

三个方法

getElementById

getElementByTagName

getElementsByName

HtmlCollection对象

  1. 有一个方法namedItem(‘name’),通过元素name特性取得集合中的项
  2. 支持按照名称访问项

2.4 document的特殊集合

document.achors返回文档中带有name属性的a元素

document.forms返回文档中所有的form元素

document.images返回文档中所有的img元素
document.links返回文档中所有带href属性的a元素

2.5 文档写入

write()  原样写入

writeln()  在字符串末尾添加一个换行符(\n)

上述两个方法相同点:

1.接收字符串作为参数,进行写入

2.可以动态写入外部资源

3.文档加载结束之后,执行这两个方法,会重写整个页面

open()

close()

3 节点(Element类型)

nodeType 1

nodeName 元素标签名

nodeValue null

parentNode Document、Element

关于tagName的比较

let doc =  document.getElementsByTagName('div')
console.log(doc[0].tagName)   //DIV

HTML中,element.tagName输出的标签名都是以大写表示

XML中,element.tagName输出的标签名与源代码保持一致

element.tagName.toLowerCase() === 'div'

3.1 HTML元素

所有HTML元素都是通过HTMLElement或者其子类表示的(每种类型都有与之相关的特性和方法)

标准特性:

id

class

title

lang 语言

dir 语言方向

className

3.1.1 操作特性:

getAttribute()

自定义特性可以通过该方法被访问到

element.elementname的方式无法访问自定义属性(IE除外)

例外:style属性

element.getAttribute('style')  // color: red;font-size: 20px 返回的是字符串
element.style // CSSStyleDeclaration{...} 返回的是一个对象

例外:事件处理程序

element.getAttribute('onclick') //alert(111) 返回的是字符串
element.onclick  // ƒ onclick(event){alert(111) }  返回的是一个函数

setAttribute()

可以操作自定义特性

使用设置的特性都会被转换为小写形式

div.setAttribute('id','hisdiv')

removeAttribute()

用于彻底删除元素特性

3.1.2 attributes属性:

输出一个元素的attributes

console.log(doc.attributes)  //NamedNodeMap{...} 伪数组

  • 元素的每个特性都由一个节点表示,这些节点存储在NamedNodeMap对象中

NameNodeMap对象的方法:

getNamedItem()  获得****nodeName等于name的节点

attr.getNamedItem('id')  // id="mydiv"

removeNamedItem() 移除nodeName等于name的节点

set****NamedItem(node)  添加节点,不常用

var div1 = document.getElementById("div1");
var type = document.createAttribute("class");
type.nodeValue = "class1";
div1.attributes.setNamedItem(type);

item(pos) 返回位于数字pos位置的节点

3.2 创建元素

createElement(name) 这个方法只接受一个参数,即要创建元素的标签名。

3.3 元素子节点

元素的childNodes属性中包含了它的所有子节点,这些子节点有可能是元素、文本节点、注释或处理指令。

4 节点(Text类型)

文本节点由Text类型表示,包含的是可以照字面解释的纯文本内容。纯文本中可以包含转义后的HTML字符,但不能包含HTML代码。

nodeType 3

nodeName #text

nodeValue 节点包含的文本

parentNode 是Element节点

不支持子节点

可以通过下列方法操作节点中的文本:

  • appendData(text):将text添加到节点的末尾。
  • deleteData(offset, count):从offset指定的位置开始删除count个字符。
  • insertData(offset, text):在offset指定的位置插入text。
  • replaceData(offset, count, text):用text替换从offset指定的位置开始到offset+count为止处的文本。
  • splitData(offset):从offset指定的位置将当前文本, 节点分成两个文本节点。
  • substringData(offset, count):提取从offset指定的位置开始到offset+count为止处的字符串。

创建文本节点
可以使用document.createTextNode()创建新文本节点,这个方法接受一个参数——要插入节点中的文本。

规范化文本节点
如果在一个包含两个或多个文本节点的父元素上调用normalize()方法,则会将所有文本节点合并成一个节点,结果节点的nodeValue等于将合并前每个文本节点的nodeValue值拼接起来的值。

分割文本节点
Text类型提供了一个作用与normalize()相反的方法:splitText()。这个方法将一个文本节点分成两个文本节点,即按照指定的位置分割nodeValue值。原来的文本节点将包含从开始到指定位置之前的内容,新文本节点将包含剩下的文本。

5 节点(Comment类型)

注释在DOM中是通过Comment类型来表示的。

nodeType 8

nodeName #comment

nodeValue 注释内容

parentNode 是Element节点,或者Document节点

不支持子节点

Comment类型与Text类型继承自相同的基类,因此它拥有除splitText()之外的所有字符串操作方法。与Text类型相似,也可以通过nodeValue或data属性来取得注释的内容。

可以使用document.createComment()并为其传递注释文本创建注释节点。

6 节点(DocumentType类型)

包含文档的doctype相关所有信息

nodeType 10

nodeName 值为doctype名称

nodeValue null

parentNode 是Document节点

不支持子节点

在DOM1级中,DocumentType对象不能动态创建,而只能通过解析文档代码的方式来创建。支持它的浏览器会把DocumentType对象保存在document.doctype中。

DOM1级描述了DocumentType对象的三个属性:name、entities和notations。其中,name属性表示文档类型的名称;entities是由文档类型描述的实体的NamedNodeMap对象;notations是由文档类型描述的符号的NamedNodeMap对象;只有name属性是有用的。这个属性保存的是文档类型的名称,也就是出现在<DOCTYPE之后的文本。

7 节点(DocumentFragment类型)

在所有节点类型中,只有DocumentFragment在文档中没有对应的标记。虽然不能把文档片段直接添加到文档中,但可以将它作为一个“仓库”来使用

如果将文档中的节点添加到文档片段中,就会从文档树中移除该节点,也不会从浏览器中再看到该节点。添加到文档片段中的新节点同样也不属于文档树

可以通过appendChild()或insertBefore()将文档片段中内容添加到文档中。在将文档片段作为参数传递给这两个方法时,实际上只会将文档片段的所有子节点添加到相应位置上文档片段本身永远不会成为文档树中的一部分

<ul id="myList"></ul>

假设我们想为这个

    元素添加3个列表项。如果逐个地添加列表项,将会导致浏览器反复渲染(呈现)新信息。为避免这个问题,可以使用一个文档片段来保存创建的列表项,然后再一次性将它们添加到文档中。

    var fragment = document.createDocumentFragment();
    var ul = document.getElementById("myList");
    var li = null;
    
    for(var i = 0; i < 3; i++) {
        li = document.createElement("li");
        li.appendChild(document.createTextNode("Item " + (i + 1)));
        fragment.appendChild(li);
    }
    
    ul.appendChild(fragment);
    

    8 节点(Attr类型)

    元素特性在DOM中以Attr类型表示

    Attr对象有三个属性:name、value和specified。其中,name是特性名称(与nodeName的值相同),value是特性的值(与nodeValue的值相同),而specified是一个布尔值,用以区别特性是在代码中指定的,还是默认的。

    使用document.createAttribute()并传入特性的名称可以创建新的特性节点。例如:

    var attr = document.createAttribute("align");
    attr.value = "left";
    element.setAttributeNode(attr);
    alert(element.attributes["align"].value);   //"left"
    alert(element.getAttributeNode("align").value);   //"left"
    alert(element.getAttribute("align"));   //"left"
    

    9 DOM操作技术

    9.1 动态脚本
    跟操作HTML元素一样,创建动态脚本也有两种方式:插入外部文件和直接插入Javascript代码。

    9.2 动态样式
    与动态脚本类似,所谓动态样式是指在页面加载时不存在的样式;动态样式是在页面加载完成后动态添加到页面中的。

    10 区别

    深入理解javascript中的动态集合——NodeList、HTMLCollection和NamedNodeMap

    www.cnblogs.com/xiaohuochai…