5. DOM
5.1 document对象
5.1.1 DOM的含义
文档对象模型(Document Object Model)。
5.1.2 document对象概述
document对象是文档的根节点,window.document属性就指向它。
document.childNodes属性返回该对象的所有子节点。
一般来说,document对象的第一个子节点是document.doctype,第二个子节点是document.documentElement。
5.1.3 document对象的属性
5.1.3.1 文档信息属性
title:文档的标题。
lastModified:文档文件的上一次修改时间。
referrer:文档的访问来源。
URL:文档的URL。
5.1.3.2 指向其他节点或对象的属性
doctype:文档类型节点。
documentElement:html元素节点。
head:head元素节点。
body:body元素节点。
5.1.3.3 指向特定元素集合的属性
document.forms :所有的form元素。
document.images:所有的img元素。
document.links:所有的a元素。
document.scripts:所有的script元素。
document.styleSheets:所有的link或者style元素。
5.1.3.4 implementation属性
该属性指向一个对象,提供浏览器支持的模块信息,它的hasFeature方法返回一个布尔值,表示是否支持某个模块。
document.implementation.hasFeature('MutationEvents','2.0') // true
5.1.4 document对象的方法
5.1.4.1 document.write()
document.write方法用于向页面写入内容。如果在页面已经渲染完成的情况下调用这个方法,会把原有的页面全部抹去,等于是在一个新建的页面上写入内容。
所以,一般document.write只能在页面渲染的过程中使用。
<div>
<script type="text/javascript">
document.write("<h1>Main title</h1>")
</script>
</div>
5.1.4.2 querySelector(),getElementById()
querySelector使用CSS选择器语法(还可以接受复杂的CSS选择器),
getElementById使用id属性(更高效)。
找不到返回null。
document.querySelector('#myElement')
document.getElementById('myElement')
5.1.4.2 querySelectorAll(),getElementsByTagName(),getElementsByClassName()
document.querySelectorAll('DIV:not(.ignore)');
document.getElementsByTagName('li')
document.getElementsByClassName('liClass')
5.1.4.3 getElementsByName()
用于选择拥有name属性的HTML元素,比如form、img、frame、embed和object。返回值是一组对象。
var forms = document.getElementsByName("x");
forms[0].tagName // "FORM"
5.1.4.4 createElement(),createTextNode()
createElement方法用来生成元素节点,参数是元素节点的tagName属性
createTextNode方法用来生成文本节点。参数是要生成的文本节点的内容。
var elementNode = document.createElement('div');
var textNode = document.createTextNode('Hi');
5.1.4.5 hasFocus()
返回布尔值,表示当前文档之中是否有元素被激活或获得焦点。
focused = document.hasFocus();
5.2 Node对象
5.2.1 Node节点对象
DOM就是由Node组成的。Node分外:
- DOCUMENT_NODE 文档节点(window.document)、
- ELEMENT_NODE 元素节点、
- ATTRIBUTE_NODE 属性节点(比如class="right")、
- TEXT_NODE 文本节点、
- DOCUMENT_FRAGMENT_NODE 文档碎片节点
- DOCUMENT_TYPE_NODE 文档类型节点。
浏览器原生提供一个Node对象,上面所有类型的节点都是Node对象派生出来的,它们都继承了Node的属性和方法。
对于HTML文档,节点有以下类型:
5.2.1.1 Node对象的属性
1、nodeName属性和nodeType属性
nodeName节点的名称,nodeType节点的常数值。
类型 | nodeName | nodeType |
---|---|---|
ELEMENT_NODE | 大写的HTML元素名 | 1 |
ATTRIBUTE_NODE | 等同于Attr.name | 2 |
TEXT_NODE | #text | 3 |
2、nodeValue属性
Text节点的nodeValue属性返回文本内容,其他的节点都返回null。
3、childNodes属性和children属性
childNodes返回所有子节点
children返回成员为HTML元素类型的子节点
4、指向其他节点的属性
firstChild:第一个子节点。
lastChild:最后一个子节点。
。。。
5.2.1.2 Node对象的方法
appendChild()
cloneNode()
compareDocumentPosition()
contains()
hasChildNodes()
insertBefore()
isEqualNode()
removeChild()
replaceChild()
5.2.2 Element对象
5.2.2.1 属性
每个HTML标签,都会转化成一个Element对象节点。
所有的Element节点的nodeType属性都是1,但是不同标签生成的节点是不一样的。
1、innerHTML属性,outerHTML属性,textContent属性,innerText属性,outerText属性
2、tagName属性
tagName属性返回该节点的HTML标签名,与nodeName属性(大写)相同。
document.querySelector('a').tagName // A
3、attributes属性
var atts = document.querySelector('a').attributes;
for(var i=0; i< atts.length; i++){
console.log(atts[i].nodeName +'='+ atts[i].nodeValue);
}
5.2.2.2 className属性和classList属性
都返回HTML元素的class属性。
<div class="one two three" id="myDiv"></div>
document.getElementById('myDiv').className
// "one two three"
document.getElementById('myDiv').classList
// {
// 0: "one"
// 1: "two"
// 2: "three"
// length: 3
// }
classList对象有一系列方法。
add():增加一个class。
remove():移除一个class。
contains():检查该DOM元素是否包含某个class。
toggle():将某个class移入或移出该DOM元素。
item():返回列表中某个特定位置的class。
toString():将class的列表转为字符串。
比较className和classList写法的区别。
document.getElementById('foo').className += 'bold';
document.getElementById('foo').classList.add('bold');
document.getElementById('foo').classList.remove('bold');
document.getElementById('foo').className =
document.getElementById('foo').className.replace(/^bold$/, '');
5.2.2.3 html元素
html元素是网页的根元素,document.documentElement就指向它。
1、clientWidth属性,clientHeight属性
返回视口(用户当前能够看见的那部分,不包括滚动条)的大小。
他两基本上与window.innerWidth和window.innerHeight同义。只有一个区别,后者包括了滚动条。
(2)offsetWidth属性,offsetHeight属性
这两个属性返回html元素的宽度和高度,即网页的总宽度和总高度。
5.2.2.4 dataset属性
dataset属性用于操作HTML标签的data-*属性。
<div id="myDiv" data-id="myId"></div>
var id = document.getElementById("myDiv").dataset.id;
document.getElementById("myDiv").dataset.id = "hello"; //赋值或添加
delete document.getElementById("myDiv").dataset.id //删除
注意:dataset属性使用骆驼拼写法表示属性名,这意味着data-hello-world会用dataset.helloWorld表示。而如果此时存在一个data-helloWorld属性,该属性将无法读取。
5.2.2.5 页面位置相关属性
1、offsetParent属性、offsetTop属性和offsetLeft属性
2、clientWidth属性和clientHeight属性
3、scrollHeight属性和scrollWidth属性
4、scrollTop属性和scrollLeft属性
5.2.2.6 style属性
style属性用来读写页面元素的行内CSS属性,详见 5.4
5.2.2.7 Element对象的方法
略
5.2.2.8 setAttribute(),removeAttribute()
<div id="foo"></div>
document.getElementById('foo').setAttribute('role', 'button');
//<div id="foo" role="button"></div>
document.getElementById('foo').removeAttribute('role');
5.2.2.9 insertAdjacentHTML()
将一段字符串,作为HTML或XML对象,插入DOM。通常用这个方法添加新节点。
document.getElementById("box2").insertAdjacentHTML('beforebegin', '<div><p>This gets inserted.</p></div>');
第一个是插入的位置,第二个是插入的节点字符串。
关于插入的位置,可以取值:beforebegin、afterbegin、beforeend、afterend。
5.2.2.10 getBoundingClientRect方法
略
5.2.2.11 table元素
表格有一些特殊的DOM操作方法。
insertRow():在指定位置插入一个新行(tr)。
deleteRow():在指定位置删除一行(tr)。
insertCell():在指定位置插入一个单元格(td)。
deleteCell():在指定位置删除一个单元格(td)。
5.2.3 Text节点
文本对应Text节点,哪怕只有一个空格,也会形成文本节点。
5.3 DOM事件
5.3.1 概述
DOM定义了一些事件,并且允许开发者通过以下3个方式指定事件的回调函数。
1、HTML属性定义
<body onclick="console.log('触发事件')">
2、Element对象的事件属性
div.onclick = function(event){
console.log('触发事件');
};
3、addEventListener方法,removeEventListener方法
button.addEventListener('click',
function(){console.log('Hello world');},
false);
其中第3个参数默认为false,表示回调函数只在冒泡阶段被触发。
5.3.2 事件的传播
5.3.2.1 传播的三个阶段
第一阶段:从文档的根元素(html元素)传导到目标元素,称为“捕获阶段”。
第二阶段:在目标元素上触发,称为“目标阶段”。
第三阶段:从目标元素传导回文档的根元素,称为“冒泡阶段”。
浏览器总是假定click事件的目标对象,是嵌套最深的那个元素。
5.3.2.2 事件的代理
由于事件有冒泡阶段,因此可以把子元素的回调函数定义在父元素上统一处理。这种方法叫做事件的代理。
var ul = document.querySelector('ul');
ul.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() === 'li') {
// some code
}
});
5.3.3 事件的类型
DOM支持多种事件。
5.3.3.1 用户界面事件
1、load事件,error事件
对资源的加载,成功了触发load事件,失败了触发error事件。
error事件不会冒泡。以防止引发父元素的error事件回调函数。
2、unload事件
卸载资源时触发。
3、beforeunload事件
在用户关闭网页时触发。它会自动跳出一个确认对话框,如果用户点击“取消”按钮,网页就不会关闭。
window.onbeforeunload = function() {
if (textarea.value != textarea.defaultValue) {
return '你确认要离开吗?';
}
};
4、resize事件
改变浏览器窗口大小时触发。
5、abort事件
资源在加载成功前停止加载时触发该事件,主要发生在element、XMLHttpRequest、XMLHttpRequestUpload对象。
6、scroll事件
用户滚动窗口或某个元素时触发该事件,主要发生在element、document、window对象。
7、contextmenu事件
用户鼠标右击某个元素时触发,主要发生在element对象。
5.3.3.2 焦点事件
事件名称 | 涵义 | 事件的目标 | |
---|---|---|---|
blur | 元素丧失焦点 | Element(除了body和frameset元素) | Document |
focus | 元素获得焦点 | Element(除了body和frameset元素) | Document |
focusin | 元素即将获得焦点,在focus之前触发 | Element | |
focusout | 元素即将丧失焦点,在blur之前触发 | Element |
5.3.3.3 表单事件
1、change事件
一些特定的表单元素(比如文本框和输入框)失去焦点、并且值发生变化时触发。
2、reset事件
表单重置(reset)时触发。
3、submit事件
表单提交(submit)时触发。
4、select事件
用户在文本框或输入框中选中文本时触发。
5.3.3.4 鼠标事件
1、click事件
它的定义是同一个位置完成一次mousedown和mouseup动作。它们的触发顺序是:mousedown,mouseup,最后click。
可以利用click事件进行CSRF(跨站请求伪造Cross-site request forgery)攻击。
2、dblclick事件
用户在element、document、window对象上用鼠标双击时触发。该事件会在mousedown、mouseup、click之后触发。
3、mousedown事件
4、mouseup事件
5、mouseenter事件
该事件与mouseover事件相似,区别在于mouseenter事件不会冒泡,而且当鼠标移出子元素的边界、当仍在父元素之中时,它不会在父元素上触发。
6、mouseleave事件
该事件与mouseout事件类似,区别在于mouseleave事件不会冒泡,而且要等到鼠标离开该元素本身和它的所有子元素时才触发。
7、mousemove事件
当鼠标持续移动时,该事件会连续触发。(性能)
8、mouseout事件
9、mouseover事件
10、wheel事件
用户滚动鼠标的滚轮时触发。
5.3.3.5 键盘事件
1、keydown事件
2、keypress事件
用户按下某个键时触发。如果用户一直按着,这个事件就持续触发。
3、keyup事件
//捕捉用户按下Ctrl+H键的代码
document.addEventListener('keydown', function(event) {
if (event.ctrlKey && event.which === 72) {
// open help widget
}
});
5.3.3.6 document对象的特有事件
1、readystatechange
在readyState属性发生变化时触发。它的发生对象是document和XMLHttpRequest对象。
2、DOMContentLoaded
在网页解析完成时触发,此时各种外部资源(resource)还没有被完全下载。也就是说,这个事件比load的触发早得多。
5.3.3.7 拖拉事件
1、drag
drag事件在源对象被拖拉过程中触发。
2、dragstart,dragend
dragstart事件在用户开始用鼠标拖拉某个对象时触发,dragend事件在结束拖拉时触发。
3、dragenter,dragleave
dragenter事件在源对象拖拉进目标对象后,在目标对象上触发。dragleave事件在源对象离开目标对象后,在目标对象上触发。
4、dragover事件
dragover事件在源对象拖拉过另一个对象上方时,在后者上触发。
5、drop事件
当源对象被拖拉到目标对象上方,用户松开鼠标时,在目标对象上触发drop事件。
5.3.3.8 CSS事件
transitionEnd
animationstart,animationend,animationiteration
5.3.4 event对象
当事件发生以后,会生成一个事件对象event,在DOM中传递,也被作为参数传给回调函数。
IE8及以下版本,这个事件需要通过window对象的event属性读取,所以要获取这个对象,往往写成下面这样。
function myEventHandler(event) {
var actualEvent = event || window.event;
// handle actualEvent
}
5.3.4.1 event对象的属性
type:返回一个字符串,表示事件的名称。
target:返回一个Element节点,表示事件起源的那个节点。
keyCode:返回按键对应的ASCII码。
ctrlKey:返回一个布尔值,表示是否按下ctrl键。
5.3.4.2 click事件
click的event还包括:
pageX,pageY:点击位置相对于html元素的坐标,单位为CSS像素。
clientX,clientY:点击位置相对于视口(viewport)的坐标,单位为CSS像素。
screenX,screenY:点击位置相对于设备显示屏幕的坐标,单位为设备硬件的像素。
5.3.4.3 event对象的方法
略
5.3.5 自定义事件
用户还可以自定义事件,然后手动触发。
$('some-element').trigger('my-custom-event');
这是jQuery定义的trigger事件,它会层层向上冒泡。冒泡过程中,如果有一个元素定义了该事件的回调函数,该回调函数就会触发。
也可以使用浏览器原生方法创造自定义事件。
5.4 CSS操作
5.4.1 DOM元素的CSS操作
5.4.1.1 HTML元素的style属性
操CSS的最简单方法:通过DOM的getAttribute、setAttribute和removeAttribute方法。
div.setAttribute('style','background-color:red;');
5.4.1.2 style对象
DOM还提供style属性,指向一个对象(简称style对象),用来读写元素的行内CSS样式。
var divStyle = document.querySelector('div').style;
divStyle.backgroundColor = 'red';
divStyle.width = '100px';
1、style对象的属性名
它等于:去掉CSS规则名的横杠,横杠后的第一个字母大写。
如:background-color 改为 backgroundColor。
如果CSS规则名是js保留字,则改为“css”+规则名。如:float 改为 cssFloat。
注意,style对象的属性值都是字符串且包括单位。所以,divStyle.width不能设置为100,而要设置为'100px'。
2、style对象的cssText属性
用来读写或删除整个style属性。
divStyle.cssText = 'background-color:red;height:100px;width:100px;';
3、CSS模块的侦测
“CSS模块的侦测”是判断当前浏览器是否支持某个模块。
常用方法是,判断DOM元素的style对象的某个属性值是否为字符串。
typeof element.style.animationName === 'string';
typeof element.style.transform === 'string';
有时候,需要把不同浏览器的CSS规则前缀也考虑进去。
typeof document.getElementById("content").style['-webkit-animation'] === 'string'
4、style对象的方法
setPropertyValue(propertyName,value) // 写
getPropertyValue(propertyName) // 读
removeProperty(propertyName) // 删除
5、style对象的animation-play-state属性
用来控制暂停动画的播放。该属性需要加上浏览器前缀。
element.style.webkitAnimationPlayState = "paused";
element.style.webkitAnimationPlayState = "running";
5.4.1.3 CSS伪元素
CSS伪元素是通过CSS向DOM添加的元素,主要方法是通过“:before”和“:after”生成伪元素,然后用content属性指定伪元素的内容。
5.4.1.4 CSS事件
动画(animation)事件
过渡(transition)事件
5.4.2 样式表
5.4.2.1 获取样式表
document对象的styleSheets属性,包含一个类似数组的对象,里面是当前文档所有的link元素(指向样式表)和style元素。
var sheets = document.styleSheets;
var sheet = document.styleSheets[0];
5.4.2.2 样式表对象
样式表对象有许多属性和方法。
cssRules属性指向一个类似数组的对象,它的每个成员就是一条CSS规则,其cssText属性就是CSS规则的字符串。
var sheet = document.querySelector('#styleElement').sheet;
sheet.cssRules[0].cssText
// "body { background-color: red; margin: 20px; }"
insertRule和deleteRule方法 用于插入和删除CSS规则。
disabled属性 用于打开或关闭一张样式表。
5.4.2.3 添加样式表
添加内置样式表,就是在文档中添加style节点。
添加外部样式表,就是在文档中添加link节点。
var linkElm = document.createElement('link');
linkElm.setAttribute('type', 'text/css');
linkElm.setAttribute('href', 'reset-min.css');
document.head.appendChild(linkElm);
5.4.3 window.getComputedStyle方法
getComputedStyle方法返回一个HTML元素的最终样式信息的对象。
5.5 拖放操作
5.5.1 拖放操作
5.5.1.1 网页元素的draggable属性
draggable用于标识元素是否可以拖动。
在大多数浏览器中,a元素和img元素默认是可以拖放的。
5.5.1.2 事件
略
5.5.2 自定义网页元素(Custom Element)
通过JavaScript可以自定义网页元素。使用前,用document对象的registerElement方法登记该元素。
5.6 Mutation Observer
Mutation Observer(变动观察器)是监视DOM变动的接口。当DOM对象树发生任何变动的时候,Mutation Observer会得到通知。
它与事件有一个本质不同:事件是同步触发;Mutation Observer则是异步触发。