什么是 DOM
文档对象模型 ( Document Object Model ) 是 HTML 和 XML 文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象 ( 包含属性和方法 ) 组成的结构集合。简言之,它会将 WEB 页面和脚本或程序语言来连接起来
一个 WEB 页面是一个文档,这个文档可以在浏览器窗口或作为 HTML 源码显示出来。但上述两个情况中都是同一份文档,文档对象模型 ( DOM ) 提供了对同一份文档的另一种表现,存储和操作的方式。DOM 是 WEB 页面的完全面向对象的表述,它能够使用如 JavaScript 等脚本语言进行修改
什么是 HTML DOM
HTML DOM 是 HTML 的标准对象模型和编程接口,它定义了:
- 作为对象的 HTML 元素
- 所有 HTML 元素的属性
- 访问所有 HTML 元素的方法
- 所有 HTML 元素的事件
通过这个对象模型,JavaScript 可以获得创建动态 HTML 的所有力量:
- JavaScript 能改变页面中的所有 HTML 元素
- JavaScript 能改变页面中的所有 HTML 属性
- JavaScript 能改变页面中的所有 CSS 样式
- JavaScript 能删除已有的 HTML 元素和属性
- JavaScript 能添加新的 HTML 元素和属性
- JavaScript 能对页面中所有已有的 HTML 事件作出反应
- JavaScript 能在页面中创建新的 HTML 事件
DOM 操作
HTML DOM 节点
在 HTML DOM 中,每一个元素都是 节点
- 文档是一个文档节点
- 所有的 HTML 元素都是元素节点
- 所有的 HTML 属性都是属性节点
- 文本插入到 HTML 元素是文本节点
- 注释是注释节点
Document 对象
当浏览器载入 HTML 文档,它就会成为 Document 对象
Document 对象是 HTML 文档的根节点
Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问
常用属性
属性 | 描述 |
---|---|
document.activeElement | 返回当前获取焦点元素 |
document.cookie | 设置或返回与当前文档有关的所有cookie |
document.body | 返回当前文档的 body 元素 |
document.baseURL | 返回文档的绝对基础URL |
document.documentElement | 返回文档根节点 |
document.domain | 返回当前文档的域名 |
document.forms | 返回当前文档中所有 Form 对象引用 |
document.images | 返回当前文档中所有 image 对象引用 |
document.links | 返回文档中所有链接对象引用 |
document.head | 返回文档 head 元素 |
document.referrer | 返回载入当前文档的文档URL |
document.title | 返回当前文档的标题 |
document.URL | 返回文档完整URL |
document.readyState | 返回当前文档加载状态 |
document.characterSet | 返回当前文档使用的字符集 |
获取元素
(1) 通过 id属性 获取元素对象
返回值为 元素对象
var oDiv = document.getElementById("id值");
(2) 通过 标签名字 获取元素对象
返回值为 元素数组
var oDiv = document.getElementsByTagName("标签名");
(3) 通过 class属性 获取元素对象
返回值为 元素数组
var oDiv = document.getElementsByClassName("class值")
(4) 通过 name值 获取元素对象
返回值为 元素数组
var oDiv = document.getElementsByName("name值")
(5) 通过 CSS选择器 获取元素对象
# 返回文档中匹配 CSS选择器 的第一个元素
document.querySelector("CSS选择器")
# 返回文档中匹配 CSS选择器 的所有元素
document.querySelectorAll("CSS选择器");
Element对象
元素对象 ( Element ) 代表着一个 HTML 元素
元素对象的 子节点 可以是 元素节点,文本节点,注释节点
基本属性
属性 | 描述 |
---|---|
element.attributes | 返回元素的属性数组 |
element.offsetHeight | 返回元素的高度(包括border和padding) |
element.offsetWidth | 返回元素的宽度(包括border和padding) |
element.offsetLeft | 返回元素距离父元素左侧的距离(父元素需要具备定位属性) |
element.offsetTop | 返回元素距离父元素顶部的距离(父元素需要具备定位属性) |
属性修改
函数 | 描述 |
---|---|
element.hasAttributes() | 判断元素是否具有属性 |
element.hasAttribute(attr) | 判断元素是否具有指定属性 |
element.setAttribute(attr,value) | 给元素设置属性 |
element.getAttribute(attr) | 获取指定属性 |
element.removeAttribute(attr) | 删除指定属性 |
节点操作
属性 | 描述 |
---|---|
element.children | 返回元素子元素节点 |
element.firstElementChild | 返回元素第一个元素节点 |
element.lastElementChild | 返回元素最后一个元素点 |
element.previousElementSibling | 返回元素上一个兄弟元素 |
element.nextElementSibling | 返回元素下一个兄弟元素 |
element.parentNode | 返回元素父节点 |
element.hasChildNodes() | 判断元素是否具有子元素 |
样式操作
1. element.style 读取/修改样式
// 获取元素对象
var div = document.getElementById("div");
// 获取样式
console.log(div.style.backgroundColor)
// 修改样式
div.style.backgroundColor = "red";
2. getComputedStyle 获取样式
// 获取元素对象的 CSS样式 数组
var style = window.getComputedStyle(元素对象[,"伪类"]);
console.log(style);
两者区别
-
只读和读写
getComputedStyle
方法是只读的,只能获取样式,不能设置;element.style
能读能写
-
获取属性的范围
getComputedStyle
方法获取的是最终应用在元素上的所有 CSS属性对象;element.style
只能获取 style 属性中的 CSS样式。
对于一个光秃秃的元素 <p>
,element.style
在获取样式方面就不如 getComputedStyle
方法了!
文本操作
属性 | 描述 |
---|---|
element.innerHTML | 设置和查看标签内容,包含 HTML 格式 |
element.innerText | 设置和查看标签内容,仅支持纯文本内容 |
元素/节点 增删
创建标签
var btu = document.createElement("button");
创建文本节点
var text = document.createTextNode("hello");
克隆节点
cloneNode(deep)
克隆一个节点,deep 设置为 true 将递归克隆内部节点
// 获取 div 元素
var div = div.insertBefore(h1,div.firstChild);
// 克隆 div 元素
var new_div = div.cloneNode()
添加节点
appendChild(node)
添加一个节点到末尾
// 创建一个 h1 标签
var h1 = document.createElement("h1");
// 创建一个 文本节点
var text = document.createTextNode("hello");
// 将 文本节点 添加到 h1标签中
h1.appendChild(text);
插入节点
insertBefore(new_node,old_node)
插入一个节点到某个节点之前
// 创建一个 h1 标签
var h1 = document.createElement("h1");
// 获取 div 元素
var div = document.getElementById("item");
// 插入 h1 标签到父节点第一个位置
div.insertBefore(h1,div.firstChild);
删除节点
removeChild(node)
删除一个子节点
// 获取 div 元素
var div = document.getElementById("item");
// 删除 div 元素最后一个子节点
div.removeChild(div.lastChild)
事件
事件是 JavaScript 与 HTML 交互的基础,要实现用户与页面的交互,先要对目标元素绑定特定的事件,设置事件处理函数,然后用户触发事件,事件处理函数执行,产生交互效果
事件类型
在 HTML DOM 中有两种事件传播的方法:冒泡和捕获
事件传播是一种定义当发生事件时元素次序的方法,假如 <div>
元素内有一个 <p>
,然后用户点击了这个 <p>
元素,应该首先传递哪个元素的 click 事件?
在冒泡中,最内侧元素的事件会首先处理,然后是更外侧的:首先处理 <p>
元素的点击事件,然后是 <div>
元素的点击事件
在捕获中,最外侧元素的事件会首先被处理,然后是更内侧的:首先处理 <div>
元素的点击事件,然后是 <p>
元素的点击事件
绑定事件
(1) DOM 0级事件
<button id="btu">提交</button>
<script>
var btu = document.getElementById("btu");
// 绑定事件
btu.onclick = function(){
console.log("hello!");
};
// 解绑事件
btu.onclick = null;
</script>
缺点:无法设置多个事件处理函数
(2) DOM 2级事件
<button id="btu">提交</button>
<script>
var btu = document.getElementById("btu");
// 绑定事件
btu.addEventListener("click",showFn,false);
btu.addEventListener("click",showFn2,false);
function showFn(){
console.log("hello fn1");
};
function showFn2(){
console.log("hello fn2");
}
// 解绑事件
btn.removeEventListener("click",showFn,false);
</script>
可以为元素绑定多个事件处理函数,可以通过第三个参数设置事件类型,默认为 false,将使用冒泡传播,如果设置为 true,则为捕获传播
Event 对象常见应用
(1) event.preventDefault()
如果调用这个方法,元素默认事件行为将不再触发。
什么是默认事件呢?例如表单 点击提交按钮跳转页面,a标签默认页面跳转或是锚点定位等
很多时候我们使用 a标签仅仅是想当做一个普通的按钮,点击实现一个功能,不想页面跳转
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
var a = document.getElementById("test");
// 此时,点击a标签只会打印消息,而不会进行页面跳转
a.onclick = function(e){
console.log();
e.preventDefault();
}
</script>
(2) event.stopPropagation()
阻止事件冒泡到父元素
前边提到事件冒泡是指事件从目标节点自下而上向 window对象传播的阶段,添加 event.stopPropagation()
这句话后,就阻止了父事件的执行
(3) event.stopImmediatePropagation();
即能阻止事件向父元素冒泡,也能阻止元素同事件类型的其它***被触发
例如,一个按钮元素绑定了多个 click 事件,当在某个 click() 事件中添加了 event.stopImmediatePropagation();
后,不仅阻止了父事件的执行,还阻止了其它 click 事件的执行
事件代理
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方法叫做事件的代理(delegation)
优点:
- 减少内存消耗,提高性能
假设有一个列表,列表之中有大量的列表项,我们需要在点击每个列表项的时候响应一个事件
如果给每个列表项一一绑定一个函数,那对于内存的消耗是非常庞大的,效率上需要消耗很多性能,借助事件代理,我们只需要给父容器 ul 绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的 click行为触发,然后把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而完成不同的事
- 动态绑定事件
很多时候,我们需要动态的增删列表项元素,如果一开始给每个子元素绑定事件,那么在列表发生变化时,就需要重新给新增的元素绑定事件,给即将删除的元素解绑事件,如果用事件代理就会省去很多这样的麻烦!