DOM
文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标记语言的标准编程接口。它是一种与平台和语言无关的应用程序接口(API),它可以动态地访问程序和脚本,更新其内容、结构和 www 文档的风格(目前,HTML 和 XML 文档是通过说明部分定义的)。文档可以进一步被处理,处理的结果可以加入到当前的页面。DOM 是一种基于树的 API 文档,它要求在处理过程中整个文档都表示在存储器中。
DOM 树
DOM 又称为文档树模型
文档:一个网页可以称为文档
节点:网页中的所有内容都是节点 (标签、属性、文本、注释等)
元素:网页中的标签
属性:标签的属性
DOM 获取页面元素
根据 id 获取元素
方法:调用 document 对象的 getElementById 方法。
参数:字符串类型的 id 的属性值。
返回值:对应 id 名的元素对象。
注意1:由于 id 名具有唯一性,部分浏览器支持直接使用 id 名访问元素,但不是标准方式,不推荐使用。
注意2:代码执行顺序,如果 js 在 html 结构之前,会导致结构未加载,不能获取对应id的元素。
<p id="para">text</p>
var para = document.getElementById("para");
根据标签名获取元素
方法:调用 document 对象的 getElementsByTagName 方法。
参数:字符串类型的标签名。
返回值:同名的元素对象组成的数组。
注意1:操作数据时需要按照操作数组的方法进行。
注意2:getElementsByTagName 方法内部获取的元素是动态增加的。
<div>div1</div>
<div>div2</div>
<div>div3</div>
var divs = document.getElementsByTagName("div");
元素对象内部获取标签元素
获取的元素对象内部,本身也可以调用根据标签获取元素方法,例如 div 元素对象也可以调用getElementsByTagName 方法。
目的:缩小选择元素的范围,类似 css 中的后代选择器。
<div id="box">
<p>text1 of box1</p>
<p>text2 of box1</p>
<p>text3 of box1</p>
<p>text4 of box1</p>
</div>
var box = document.getElementById("box");
var ps = box.getElementsByTagName("p");
根据 name 获取元素
方法:调用 document 对象的 getElementsByName 方法。
参数:字符串类型的 name 属性值。
返回值:name 属性值相同的元素对象组成的数组。
不建议使用:在 IE 和 Opera 中有兼容问题,会多选中 id 属性值相同的元素。
<input type="radio" name="age">0~10<br>
<input type="radio" name="age">11~20<br>
<input type="radio" name="age">20~30<br>
var ages = document.getElementsByName("age");
根据类名获取元素
方法:调用 document 对象的 getElementsByClassName 方法。
参数:字符串类型的 class 属性值。
返回值:class 属性值相同的元素对象组成的数组。
浏览器兼容问题:不支持 IE8 及以下的浏览器
<p class="para">text2 of box1</p>
<p class="para">text3 of box1</p>
var paras = document.getElementsByClassName("para");
根据选择器获取元素
方法1:调用 document 对象的 querySelector 方法,通过 css 中的选择器去选取第一个符合条件的标签元素。
方法2:调用 document 对象的 querySelectorAll 方法,通过 css 中的选择器去选取所有符合条件的标签元素。
参数:字符串类型的 css 中的选择器。
浏览器兼容问题:不支持 IE8 以下的浏览器
<div id="box">
<p>text of box</p>
<p class="para">text2 of box</p>
<p class="para">text3 of box</p>
<p>text4 of box</p>
</div>
var para = document.querySelector("#box .para");
var paras = document.querySelectorAll("#box .para");
总结
掌握,没有兼容问题
getElementById()
getElementsByTagName()
了解
getElementsByName()
getElementsByClassName()
querySelector()
querySelectorAll()
事件
事件:在什么时候做什么事
执行机制:触发--响应机制
绑定事件(注册事件)三要素:
1、事件源:给谁绑定事件
2、事件类型:绑定什么类型的事件
3、事件函数:事件发生后执行什么内容,写在函数内部
事件监听
JavaScript 解析器会给有绑定事件的元素添加一个监听,解析器会一直监测这个元素,只要 触发对应的绑定事件,会立刻执行事件函数。
方法1:绑定 HTML 元素属性。
方法2:绑定 DOM 对象属性。
常用的鼠标事件类型
| 方法名 | 描述 |
|---|---|
| onclick | 鼠标左键单击触发 |
| ondbclick | 鼠标左键双击触发 |
| onmousedown | 鼠标按键按下触发 |
| onmouseup | 鼠标按键放开时触发 |
| onmousemove | 鼠标在元素上移动触发 |
| onmouseover | 鼠标移动到元素上触发 |
| onmouseout | 鼠标移出元素边界触发 |
<input type="button" id="btn" value="button">
<script>
var btn = document.getElementById("btn");
btn.onclick = function () {
alert("123");
};
</script>
DOM 元素属性操作
非表单元素的属性
例如:href、title、id、src 等。
调用方式:元素对象打点调用属性名,例如 obj.href。
注意:部分的属性名跟关键字和保留字冲突,会更换写法。
class → className
for → htmlFor
rowspan → rowSpan
属性赋值:给元素属性赋值,等号右侧的赋值都是字符串格式。
获取标签内部内容的属性
获取标签内部内容的属性有两个:innerHTML 和 innerText
innerHTML属性,在获取标签内部内容时,如果包含标签,获取的内容会包含标签,获取的内容包括空白换行等。
innerText属性,在获取标签内部内容时,如果包含标签,获取的内容会过滤标签,获取的内容会去掉换行和缩进等空白。
更改标签内容
还可以通过两个属性给双标签内部去更改内容:
innerHTML 设置属性值,有标签的字符串,会按照 HTML 语法中的标签加载。
innerText 设置属性值,有标签的字符串,会按照普通的字符加载。
对比使用场景
innerText:在设置纯字符串时使用。
innerHTML:在设置有内部子标签结构时使用。
表单元素属性
value 用于大部分表单元素的内容获取(option除外)
type 可以获取input标签的类型(输入框或复选框等)
disabled 禁用属性
checked 复选框选中属性
selected 下拉菜单选中属性
注意:在 DOM 中元素对象的属性值只有一个时,会被转成布尔值显示。
例如:txt.disabled = true;
自定义属性操作
getAttribute(name) 获取标签行内属性
setAttribute(name,value) 设置标签行内属性
removeAttribute(name) 移除标签行内属性
与element.属性的区别: 上述三个方法用于获取任意的行内属性,包括自定义的属性。
<div id="box" age="18" sex="male">小明</div>
<script>
var box = document.getElementById("box");
// 元素自定义的新属性不能用点语法直接调用
// 可以调用元素对象的获取自定义属性的方法
console.log(box.getAttribute("age"));
// 也可以调用自有的属性
console.log(box.getAttribute("id"));
// 设置属性,添加新的自定义属性或者自有属性
box.setAttribute("age","20");
box.setAttribute("city","Beijing");
// 传的参数不需要进行属性名的修改
box.setAttribute("class","demo");
// 移除属性
box.removeAttribute("age");
box.removeAttribute("class");
</script>
style 样式属性操作
使用 style 属性方式设置的样式显示在标签行内。
element.style 属性的值,是所有行内样式组成的一个样式对象。
样式对象可以继续点语法调用或更改 css 的行内样式属性,例如 width、height 等属性。
注意1:类似 background-color 这种复合属性的单一属性写法,是由多个单词组成的,要修改为驼峰命名方式书写 backgroundColor。
注意2:通过样式属性设置宽高、位置的属性类型是字符串,需要加上 px 等单位。
<input type="button" value="按钮" id="btn">
<div id="box">文字</div>
<script>
var btn = my$("btn");
var box = my$("box");
btn.onclick = function () {
box.style.width = "100px";
box.style.height = "200px";
box.style.backgroundColor = "yellow";
};
</script>
className 类名属性操作
修改元素的 className 属性相当于直接修改标签的类名。
如果需要修改多条 css 样式,可以提前将修改后的样式设置到一个类选择器中,后续通过修改类名的方式,批量修改 css 样式。
修改单个class可以用replace方法。
box.className.replace("hide","show");
DOM 节点操作
节点属性
nodeType 节点的类型,属性值为数字,表示不同的节点类型,共 12 种,只读
1 元素节点
2 属性节点
3 文本节点
nodeName 节点的名称(标签名称),只读
nodeValue 节点值,返回或设置当前节点的值
元素节点的 nodeValue 始终是 null
父子节点常用属性
childNodes 只读属性,获取一个节点所有子节点的实时的集合,集合是动态变化的。
children 只读属性,返回一个节点所有的子元素节点集合,是一个动态更新的 HTML 元素集合。
firstChild 只读属性,返回该节点的第一个子节点,如果该节点没有子节点则返回 null。
lastChild 只读属性,返回该节点的最后一个子节点,如果该节点没有子节点则返回 null。
parentNode 返回一个当前节点的父节点,如果没有这样的节点,比如说像这个节点是树结构的顶端或者没有插入一棵树中,这个属性返回 null。
parentElement 返回当前节点的父元素节点,如果该元素没有父节点,或者父节点不是一个 DOM 元素,则返回 null。
兄弟节点常用属性
nextSibling 只读属性,返回与该节点同级的下一个节点,如果没有返回null。
previousSibling 只读属性,返回与该节点同级的上一个节点,如果没有返回null。
nextElementSibling 只读属性,返回与该节点同级的下一个元素节点,如果没有返回null。
previousElementSibling 只读属性,返回与该节点同级的上一个元素节点,如果没有返回null。
注意:nextElementSibling 和 previousElementSibling 有兼容性问题,IE9以后才支持。
创建新节点的方法
document.createElement("div") 创建元素节点
document.createAttribute("id") 创建属性节点
document.createTextNode("hello") 创建文本节点
一般将创建的新节点存在变量中,方便使用。
节点常用操作方法 1
parentNode.appendChild(child):将一个节点添加到指定父节点的子节点列表末尾。
parentNode.replaceChild(newChild, oldChild):用指定的节点替换当前节点的一个子节点,并返回被替换掉的节点。
parentNode.insertBefore(newNode, referenceNode):在参考节点之前插入一个拥有指定父节点的子节点,referenceNode 必须设置,如果 referenceElement 为 null 则 newNode 将被插入到子节点的末尾。
parentNode.removeChild(child):移除当前节点的一个子节点。这个子节点必须存在于当前节点中。
节点常用操作方法 2
Node.cloneNode(Boolean):克隆一个节点,并且可以选择是否克隆这个节点下的所有内容。参数为 Boolean 布尔值,表示是否采用深度克隆,如果为 true,则该节点的所有后代节点也都会被 克隆,如果为 false,则只克隆该节点本身,默认值为true,节点下的内容会被克隆。
注意:克隆时,标签上的属性和属性值也会被复制,写在标签行内的绑定事件可以被复制, 但是通过 JavaScript 动态绑定的事件不会被复制。
节点常用操作方法 3
Node.hasChildNodes():没有参数,返回一个 Boolean 布尔值,来表示该元素是否包含有子节点。
Node.contains(child):返回一个 Boolean 布尔值,来表示传入的节点是否为该节点的后代节点。
DOM 事件详解
注册事件的方法1
element.addEventListener() 方法。
参数:
第一个参数:事件类型的字符串(直接书写”click”,不需要加 on)
第二个参数:事件函数
同一个元素可以多次绑定事件监听,同一个事件类型可以注册多个事件函数
兼容性问题:不支持 IE9 以下的浏览器
<input type="button" value="点击" id="btn">
<script>
var btn = document.getElementById("btn");
// DOM 2 级事件绑定方式
btn.addEventListener("click",function () {
alert(1);
});
// 多次绑定相同的事件类型,事件会根据书写的顺序进行一个事件排队
btn.addEventListener("click",clickEvent);
function clickEvent() {
alert(2);
}
// 方法不支持 IE 9 以下的浏览器
</script>
注册事件的方法2
element.attachEvent() 方法。
参数: 第一个参数:事件类型的字符串(需要加 on)
第二个参数:事件函数
同一个元素可以多次绑定事件监听,同一个事件类型可以注册多个事件函数
兼容性问题:只支持 IE10 及以下的浏览器
<input type="button" value="点击" id="btn">
<script>
var btn = document.getElementById("btn");
// DOM 2 级事件绑定方式
// 兼容:IE 10 及以下浏览器
// IE8 及以下的浏览器处理事件队列时,会出现顺序错乱
btn.attachEvent("onclick",function () {
alert(3);
});
btn.attachEvent("onclick",clickEvent);
function clickEvent() {
alert(4);
}
</script>
注册事件的兼容写法
自定义一个注册事件函数
参数:事件源,事件类型(不加 on),事件函数
IE9 及以上的浏览器,使用 addEventListener 方法
IE9 以下的浏览器,使用 attachEvent 方法
判断浏览器时,不需要判断它的版本,可以检测浏览器能力
浏览器能力检测:将某个方法的调用作为 if 语句的判断条件,如果浏览器认识该方法返回true,否则返回 false。
<input type="button" value="点击" id="btn">
<script>
var btn = document.getElementById("btn");
// 调用函数
addEvent(btn,"click",function () {
alert(1);
});
// DOM 2 级事件绑定方式
// 自己制作一个兼容所有浏览器的绑定事件的函数
// 参数:事件源,事件类型,事件函数
function addEvent(ele,type,fn) {
// IE 9 及以上的浏览器和其他浏览器,使用 addEventListener 方法
// IE 9 以下的浏览器,使用 attachEvent 方法
// 浏览器能力检测
if (ele.addEventListener) {
ele.addEventListener(type,fn);
} else if (ele.attachEvent) {
ele.attachEvent("on" + type,fn);
}
}
</script>
移除事件的其他方法1
element.removeEventListener() 方法。
参数:
第一个参数:事件类型的字符串(直接书写”click”,不需要加 on)
第二个参数:事件函数引用名
注意:没有办法移除一个匿名函数,所以在注册事件时需要单独声明一个有函数名的事件函数。
兼容性问题:不支持 IE9 以下的浏览器
<input type="button" value="点击" id="btn">
<script>
var btn = document.getElementById("btn");
//绑定事件
btn.onclick = function () {
alert(1);
};
//解除绑定方法
btn.onclick = null;
//绑定事件
btn.addEventListener("click",fun);
//解除绑定
btn.removeEventListener("click",fun);
function fun() {
alert(2);
}
</script>
移除事件的其他方法2
element.detachEvent() 方法。
参数: 第一个参数:事件类型的字符串(需要加 on) 第二个参数:事件函数
注意:没有办法移除一个匿名函数,所以在注册事件时需要单独声明一个有函数名的事件函数。
兼容性问题:只支持 IE10 及以下的浏览器
<input type="button" value="点击" id="btn">
<script>
var btn = document.getElementById("btn");
// 绑定事件
btn.attachEvent("onclick",fun);
// 解除绑定
btn.detachEvent("onclick",fun);
function fun() {
alert(2);
}
</script>
移除事件的兼容写法
自定义一个移除事件函数
参数:事件源,事件类型(不加 on),事件函数
IE9 及以上的浏览器,使用 removeEventListener 方法
IE9 以下的浏览器,使用 detachEvent 方法
建议:将自己封装的一些常用函数和方法,放到一个单独的 .js 文件中。
<input type="button" value="点击" id="btn">
<script>
var btn = document.getElementById("btn");
// 调用函数
addEvent(btn,"click",fun);
// 移除事件
removeEvent(btn,"click",fun);
function fun() {
alert(1);
}
// DOM 2 级事件绑定方式
// 自己制作一个兼容所有浏览器的绑定事件的函数
// 参数:事件源,事件类型,事件函数
function addEvent(ele,type,fn) {
// IE 9 及以上的浏览器和其他浏览器,使用 addEventListener 方法
// IE 9 以下的浏览器,使用 attachEvent 方法
// 浏览器能力检测
if (ele.addEventListener) {
ele.addEventListener(type,fn);
} else if (ele.attachEvent) {
ele.attachEvent("on" + type,fn);
}
}
// 兼容所有浏览器的 解除绑定事件的函数
// 参数:事件源,事件类型,事件函数
function removeEvent(ele,type,fn) {
// 浏览器能力检测
if (ele.removeEventListener) {
ele.removeEventListener(type,fn);
} else if (ele.detachEvent) {
ele.detachEvent("on" + type,fn);
}
}
</script>
DOM 事件流
事件流的三个阶段
第一个阶段:事件捕获
第二个阶段:事件执行过程
第三个阶段:事件冒泡
addEventListener() 第三个参数为 false 时,事件冒泡
addEventListener() 第三个参数为 true 时,事件捕获
onclick 类型:只能进行事件冒泡过程,没有捕获阶段
attachEvent() 方法:只能进行事件冒泡过程,没有捕获阶段
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
<script>
// 获取元素
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
var box3 = document.getElementById("box3");
// 添加点击事件
// addEventListener 有第三个参数,用来决定事件流的方向
// 参数值是 布尔类型的值,false 表示事件冒泡过程,true 表示事件捕获过程
// 参数默认值是 false
box1.addEventListener("click",function () {
console.log(1);
},false);
box2.addEventListener("click",function () {
console.log(2);
},false);
box3.addEventListener("click",function () {
console.log(3);
},false);
box1.addEventListener("click",function () {
console.log(this.id);
},true);
box2.addEventListener("click",function () {
console.log(this.id);
},true);
box3.addEventListener("click",function () {
console.log(this.id);
},true);
// onclick 属性添加事件方法只有冒泡过程,没有捕获过程
box1.onclick = function () {
console.log(1);
};
</script>
事件委托
利用事件冒泡,将子级的事件委托给父级加载
同时,需要利用事件函数的一个 e 参数,内部存储的是事件对象
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
// 让每个 li 被点击后,自己添加特殊的背景色,而其他兄弟不添加
// 以前的思路:获取所有的 li 标签元素,批量添加事件
// 事件委托:可以将一些子级的公共类型的事件委托给他们的父级添加,在父级内部想办法找到真正触发事件的最底层的事件源
// 获取元素
var list = document.getElementById("list");
var lis = list.children;
// 给 ul 添加点击事件
list.onclick = function (e) {
// 在内部要想办法找到真正触发事件的 li
// 借用事件函数内部的一个参数 e,e 是事件对象
// 只要触发事件,函数内部都可以得到一个事件对象,对象中存储了关于事件的一系列数据
// e.target 属性记录的就是真正触发事件的事件源
// 排除其他
for (var i = 0 ; i < lis.length ; i++) {
lis[i].style.backgroundColor = "";
}
e.target.style.backgroundColor = "pink";
};
</script>
事件对象
只要触发事件,就会有一个对象,内部存储了与事件相关的数据。
e 在低版本浏览器中有兼容问题,低版本浏览器使用的是 window.event
事件对象常用的属性:
| 方法名 | 描述 |
|---|---|
| e.eventPhase | 查看事件触发时所处的阶段 |
| e.target | 用于获取触发事件的元素 |
| e.srcElement | 用于获取触发事件的元素,低版本浏览器使用 |
| e.currentTarget | 用于获取绑定事件的事件源元素 |
| e.type | 获取事件类型 |
| e.clientX/e.clientY | 所有浏览器都支持,鼠标距离浏览器窗口左上角的距离 |
| e.pageX/e.pageY | IE8 以前不支持,鼠标距离整个HTML页面左上顶点的距离 |
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
<script>
// 获取元素
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
var box3 = document.getElementById("box3");
// 添加事件
box1.onclick = function (e) {
// e指的就是存储事件对象的参数,只要事件被触发,e就会自动接收数据
// 兼容问题
e = e || window.event;
// e.eventPhase 判断出事件执行时处于哪个阶段
// 1:捕获阶段
// 2:目标阶段
// 3:冒泡阶段
// console.log(e.eventPhase);
// 获取真正触发事件的元素
var target = e.target || e.srcElement;
// console.log(target);
// 获取绑定事件的事件源元素
console.log(e.currentTarget);
// this 指向
console.log(this);
};
</script>
<div id="box1"></div>
<script>
// 获取元素
var box1 = document.getElementById("box1");
box1.onmouseover = fn;
box1.onmouseout = fn;
// 避免添加多个函数,占用更多的内存
function fn(e) {
e = e || window.event;
// 根据事件类型,执行不同的代码
switch (e.type) {
case "mouseover":
box1.style.backgroundColor = "pink";
break;
case "mouseout":
box1.style.backgroundColor = "yellowgreen";
break;
}
}
</script>
取消默认行为和阻止事件传播的方式
| 方法名 | 描述 |
|---|---|
| e.preventDefault() | 取消默认行为 |
| e.returnValue | 取消默认行为,低版本浏览器使用 |
| e.stopPropagation(); | 阻止冒泡,标准方式 |
| e.cancelBubble = true; | 阻止冒泡,IE 低版本,标准中已废弃 |
<a id="link" href="www.baidu.com">点击</a>
<script>
var link = document.getElementById('link');
link.onclick = function (e) {
e = e || window.event;
alert('hello');
// 普通的方式阻止默认行为
// return false;
// DOM 的方法
// e.preventDefault();
// 低版本浏览器需要使用一个对象的属性
e.returnValue = false;
}
</script>
<div id="box1">
<div id="box2">
<div id="box3">
</div>
</div>
</div>
<script>
// 事件冒泡
var box1 = document.getElementById('box1');
var box2 = document.getElementById('box2');
var box3 = document.getElementById('box3');
var array = [box1, box2, box3];
for (var i = 0; i < array.length; i++) {
var box = array[i];
box.onclick = function (e) {
e = e || window.event;
console.log(this.id);
// 阻止事件冒泡
// e.stopPropagation();
// 低版本浏览器使用 属性
e.cancelBubble = true;
}
}
</script>
DOM 特效
偏移量属性
offsetParent 偏移参考父级,距离自己最近的有定位的父级,如果都没有定位参考body(html)
offsetLeft / offsetTop 偏移位置
offsetWidth / offsetHeight 偏移大小
客户端大小
client 系列没有参考父级元素。
clientLeft / clientTop 边框区域尺寸,不常用
clientWidth / clientHeight 边框内部大小
滚动偏移属性
scrollLeft / scrollTop 盒子内部滚动出去的尺寸
scrollWidth / scrollHeight 盒子内容的宽度和高度