0 DOM级别简介
0.1 DOM0级事件
0级DOM分为两种
- 行内事件:在标签中写事件
- 元素.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类型
浏览器中,
- document对象,是HTMLDocument的一个实例
- 表示整个HTML页面
- 是window对象的一个属性,可以作为全局对象访问
特点:
- nodeType 9
- nodeName #document
- nodeValue parentValue ownerDocument 都是 null
2.1 document对象的子节点
Document节点的子节点可以有四种:
-
DocumentType(文档类型, )
-
Element(元素,)
-
ProcessingInstruction(XML中的DOM)
-
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对象
- 有一个方法namedItem(‘name’),通过元素name特性取得集合中的项
- 支持按照名称访问项
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 动态样式
与动态脚本类似,所谓动态样式是指在页面加载时不存在的样式;动态样式是在页面加载完成后动态添加到页面中的。