1.概述
DOM 是 JavaScript 操作网页的接口,全称为“文档对象模型”,它的作用是将网页转为一个 JavaScript 对象,从而可以用脚本进行各种操作(比如增删内容)。
1.1DOM节点
DOM 的最小组成单位叫做节点(node)。文档的树形结构(DOM 树),就是由各种不同类型的节点组成。每个节点可以看作是文档树的一片叶子。
节点的类型有七种。
Document
:整个文档树的顶层节点DocumentType
:doctype
标签(比如<!DOCTYPE html>
)Element
:网页的各种HTML标签(比如<body>
、<a>
等)Attr
:网页元素的属性(比如class="right"
)Text
:标签之间或标签包含的文本Comment
:注释DocumentFragment
:文档的片段
浏览器提供一个原生的节点对象Node
,上面这七种节点都继承了Node
,因此具有一些共同的属性和方法。
1.2节点树
它有一个顶层节点,下一层都是顶层节点的子节点,然后子节点又有自己的子节点,就这样层层衍生出一个金字塔结构,又像一棵树。这种树状结构就是 DOM 树。
浏览器原生提供document
节点,代表整个文档。
除了根节点,其他节点都有三种层级关系。
- 父节点关系(parentNode):直接的那个上级节点
- 子节点关系(childNodes):直接的下级节点
- 同级节点关系(sibling):拥有同一个父节点的节点
2.Document 节点
document
节点对象代表整个文档,每张网页都有自己的document
对象。window.document
属性就指向这个对象。只要浏览器开始载入 HTML 文档,该对象就存在了,可以直接使用。
document
对象有不同的办法可以获取。
- 正常的网页,直接使用
document
或window.document
。 iframe
框架里面的网页,使用iframe
节点的contentDocument
属性。- Ajax 操作返回的文档,使用
XMLHttpRequest
对象的responseXML
属性。 - 内部节点的
ownerDocument
属性。
document
对象继承了EventTarget
接口和Node
接口,并且混入(mixin)了ParentNode
接口。这意味着,这些接口的方法都可以在document
对象上调用。除此之外,document
对象还有很多自己的属性和方法。
2 DOM方法
2.1document.querySelector(),document.querySelectorAll()
document.querySelector
方法接受一个 CSS 选择器作为参数,返回匹配该选择器的元素节点。如果有多个节点满足匹配条件,则返回第一个匹配的节点。如果没有发现匹配的节点,则返回null
。
var el1 = document.querySelector('.myclass');
var el2 = document.querySelector('#myParent > [ng-click]');
document.querySelectorAll
方法与querySelector
用法类似,区别是返回一个NodeList
对象,包含所有匹配给定选择器的节点。
elementList = document.querySelectorAll('.myclass');
2.2document.getElementsByTagName()
document.getElementsByTagName()
方法搜索 HTML 标签名,返回符合条件的元素。它的返回值是一个类似数组对象(HTMLCollection
实例),可以实时反映 HTML 文档的变化。如果没有任何匹配的元素,就返回一个空集。
var paras = document.getElementsByTagName('p');
paras instanceof HTMLCollection // true
2.3document.getElementsByClassName()
document.getElementsByClassName()
方法返回一个类似数组的对象(HTMLCollection
实例),包括了所有class
名字符合指定条件的元素,元素的变化实时反映在返回结果中。
参数可以是多个class
,它们之间使用空格分隔。
var elements = document.getElementsByClassName(names);
var elements = document.getElementsByClassName('foo bar');
2.4 document.getElementsByName()
document.getElementsByName()
方法用于选择拥有name
属性的 HTML 元素(比如<form>
、<radio>
、<img>
、<frame>
、<embed>
和<object>
等),返回一个类似数组的的对象(NodeList
实例),因为name
属性相同的元素可能不止一个。
// 表单为 <form name="x"></form>
var forms = document.getElementsByName('x');
forms[0].tagName // "FORM"
2.5document.getElementById()
document.getElementById()
方法返回匹配指定id
属性的元素节点。如果没有发现匹配的节点,则返回null
。
var elem = document.getElementById('para1');
2.6 document.createElement()
document.createElement() 方法是用来创建元素节点,并返回该节点。
var newDiv = document.createElement('div');
3.事件
DOM 节点的事件操作(监听和触发),都定义在EventTarget
接口。
该接口主要提供三个实例方法。
(1)addEventListener()
:绑定事件的监听函数
function hello() {
console.log('Hello world');
}
var button = document.getElementById('btn');
button.addEventListener('click', hello, false);
(2)removeEventListener()
:移除事件的监听函数
div.addEventListener('click', listener, false);
div.removeEventListener('click', listener, false);
(3)dispatchEvent()
:触发事件
EventTarget.dispatchEvent()
方法在当前节点上触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault()
,则返回值为false
,否则为true
。
para.addEventListener('click', hello, false);
var event = new Event('click');
para.dispatchEvent(event);
3.1事件捕获和冒泡
在捕获阶段依次为window
、document
、html
、body
、div
、p
,
在冒泡阶段依次为p
、div
、body
、html
、document
、window
。
3.1.1事件代理
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理。
var ul = document.querySelector('ul');
ul.addEventListener('click', function (event) {
if (event.target.tagName.toLowerCase() === 'li') {
// some code
}
});
4.Event 对象
浏览器原生提供一个Event
对象,所有的事件都是这个对象的实例,或者说继承了Event.prototype
对象。
Event
对象本身就是一个构造函数,可以用来生成新的实例。
event = new Event(type, options);
Event
构造函数接受两个参数。第一个参数type
是字符串,表示事件的名称;第二个参数options
是一个对象,表示事件对象的配置。该对象主要有下面两个属性。
bubbles
:布尔值,可选,默认为false
,表示事件对象是否冒泡。cancelable
:布尔值,可选,默认为false
,表示事件是否可以被取消,即能否用Event.preventDefault()
取消这个事件。一旦事件被取消,就好像从来没有发生过,不会触发浏览器对该事件的默认行为。
var ev = new Event(
'look',
{
'bubbles': true,
'cancelable': false
}
);
document.dispatchEvent(ev);
4.1Event.bubbles,Event.eventPhase
Event.bubbles表示当前事件是否冒泡。该属性只读。
Event.eventPhase
的返回值有四种可能。
- 0,事件目前没有发生。
- 1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。
- 2,事件到达目标节点,即
Event.target
属性指向的那个节点。 - 3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。
Event.eventPhase
属性返回一个整数常量,表示事件目前所处的阶段。该属性只读。
4.2Event.preventDefault()
阻止默认行为,如点击链接后,浏览器默认会跳转到另一个页面,使用这个方法以后,就不会跳转了。
4.3Event.stopPropagation()
阻止冒泡,该方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上其他的事件监听函数。
function stopEvent(e) {
e.stopPropagation();
}
el.addEventListener('click', stopEvent, false);
5.鼠标事件
鼠标事件种类
(1)点击事件
click:鼠标点击时触发
(2)移动事件
mouseenter 监听鼠标是否移入 DOM 元素
mouseleave 监听鼠标是否移出 DOM 元素
6.键盘事件
keydown 键盘按下触发
keyup 键盘抬起触发
7.焦点事件
focus 获得焦点
blur 失去焦点
8.其他事件
(1)scroll 事件
scroll
事件在文档或文档元素滚动时触发,主要出现在用户拖动滚动条。
window.addEventListener('scroll', callback);
(2)resize 事件
resize
事件在改变浏览器窗口大小时触发,主要发生在window
对象上面。
var resizeMethod = function () {
if (document.body.clientWidth < 768) {
console.log('移动设备的视口');
}
};
window.addEventListener('resize', resizeMethod, true);