DOM对象简介
一、什么是DOM
DOM,全称Document Object Model,文档对象模型。JDS通过DOM对象对HTML文档进行操作。
- 文档:整个HTML页面就是文档
- 对象:网页中的每个部分都是对象
- 模型:使用模型来表示对象之间的关系,方便我们获取对象
DOM树
节点
节点(Node),是构成网页最基本的组成部分,网页中的每一个部分都可以称为是一个节点。比如:html标签,属性,文本,注释,以及整个文档都是一个节点。
节点有不同的类型,不同节点的属性和方法都不尽相同
- 元素节点,HTML文档中的HTML标签
- 属性节点,HTML标签的属性
- 文本节点,HTML标签中的文本内容
- 文档节点,整个HTML文档
节点的属性
固定属性:
代码示例
<button id="btn">我是一个按钮</button>
<script>
//获取按钮对象
var btn = document.getElementById("btn");
document.write(btn); // [object HTMLButtonElement]
</script>
二、DOM事件
事件,就是用户和浏览器之间的交互行为,比如:点击按钮,鼠标移动等。
代码示例
通过属性为按钮绑定鼠标单击事件(不推荐)
<button id="btn" onclick="alert('hello!');">我是一个按钮</button>
为按钮对应事件绑定单击响应函数(推荐)
<button id="btn">我是一个按钮</button>
<script>
//获取按钮对象
var btn = document.getElementById("btn");
//为按钮btn绑定点击响应函数
btn.onclick = function(){
alert('hi');
};
</script>
1.事件对象
当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参转递进响应函数,在事件对象中封装了当前事件相关的详细信息,比如鼠标的坐标,键盘哪个键被按下,鼠标滚轮的方向等等。
- clientX获取鼠标指针的水平座标
- clientY获取鼠标指针的垂直坐标
… …
注意
在ie8及以下浏览器中,响应函数被触发时,浏览器不会传递事件对象,而是将事件对象作为window对象的属性保存。
代码示例
<style>
#mouseMove {
width: 300px;
height: 100px;
margin-bottom: 20px;
border: 1px solid #000;
}
#showMsg {
width: 300px;
height: 50px;
border: solid 1px #000;
}
</style>
<script>
/* 实现功能:当鼠标在mouseMove块中移
动时,将鼠标当前的坐标显示在showMsg块中 */
window.onload = function () {
// 获取两个块元素
var mouseMove = document.getElementById("mouseMove");
var showMsg = document.getElementById("showMsg");
// 为mouseMove块绑定鼠标移动函数
//形参event 接收浏览器传入的事件对象
mouseMove.onmousemove = function (event) {
if(event){
// 通过事件对象获取鼠标指针的坐标
var x = event.clientX;
var y = event.clientY;
}else{
/* ie8的方式:通过window.event来获取鼠标指针的坐标 */
var x = window.event.clientX;
var y = window.event.clientY;
}
// 在showMsg中显示鼠标指针坐标
showMsg.innerHTML = "x = " + x + ",y = " + y
}
}
</script>
<div id="mouseMove"></div>
<div id="showMsg"></div>
2.事件的冒泡
事件的冒牌是指事件的向上传导,当后代元素的事件被触发时,其祖先元素的相同事件也会被触发。
在开发中大部分冒泡是有用的,如果不希望事件发生冒泡,可以通过事件对象的cancelBubble属性设置,将其设置为true即可取消事件的冒泡。
冒泡的应用:事件的委派
指将事件统一绑定给元素共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,这样可以通过祖先元素的响应函数来处理事件。
<script>
window.onload = function(){
/*冒泡的应用:事件委派*/
// 给a元素的共同祖先元素ul绑定单击响应函数,这样当a被点击时会冒泡到ul触发单击事件
var ul = document.getElementById("ul1");
//但是这样做会导致点击ul的任何部分都触发单击事件
ul.onclick = function(event){
// 解决事件对象的兼容问题
event = event || window.event;
//可以利用事件对象target属性来判断触发事件的节点是谁
// target表示指向触发事件对象的节点
if(event.target.className == "link"){
alert("hello");
}
}
}
</script>
<ul id="ul1" style="background-color: coral;">
<li><a href="javasciprt:;" class="link">超链接1</a></li>
<li><a href="javasciprt:;" class="link">超链接2</a></li>
<li><a href="javasciprt:;" class="link">超链接3</a></li>
</ul>
3.事件的绑定
(1)addEventListener()方法
- 通过该方法为元素的事件绑定响应函数,可以给一个元素的相同事件绑定多个响应函数,当事件触发时,响应函数将会按照函数的绑定顺序执行。
- 参数
- 事件的字符串,不要on
- 回调函数,当事件被触发时执行该函数
- 是否在捕获阶段触发事件,一般都为false
- 不支持ie8及以下浏览器
- 该方法中this指向绑定事件的对象
(2)attachEvent()方法 - 与addEventListener()方法类似,不同的是响应函数的执行顺序是先绑定后执行
- 参数
- 事件的字符串,要on
- 回调函数
- 支持ie8及以下浏览器
- 该方法中this指向window
解决兼容问题,并统一this
function bind(obj,eventStr,callback){
// 如果对象有addEventListener()方法,则使用该方法
if(obj.addEventListener){
obj.addEventListener(eventStr,callback,false);
}else{
// 如果没有,就使用attachEvent()方法
obj.attachEvent("on"+eventStr,function(){
//使用call()来调用callback,解决attachEvent()方法中this指向window的情况
callback.call(obj);
});
}
}
4.事件的传播
事件的传播分为三个阶段
- 1.捕获阶段,在捕获阶段时,从最外层的祖先元素向目标元素进行事件的捕获,但是不会触发事件
- 2.目标阶段,事件捕获到目标元素,捕获结束,开始在目标元素上触发事件
- 3.冒泡阶段,事件从目标元素向它的祖先元素传递,一次触发祖先上的事件
如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true。
5.DOM事件练习
创建一个拖拽函数
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#box1 {
width: 100px;
height: 100px;
background-color: #fad;
position: absolute;
}
</style>
<script>
window.onload = function () {
function drag(obj) {
// 给box1绑定鼠标按下事件
obj.onmousedown = function (event) {
event = event || window.event;
// 获取div的偏移量
var offsetL = event.clientX - obj.offsetLeft;
var offsetT = event.clientY - obj.offsetTop;
// 当鼠标按下时,给document绑定鼠标移动事件
document.onmousemove = function (event) {
event = event || window.event;
// 获取鼠标当前位置
var left = event.clientX - offsetL;
var top = event.clientY - offsetT;
// 将box1移动到鼠标当前位置
obj.style.left = left + "px";
obj.style.top = top + "px";
}
// 当鼠标松开时,将鼠标移动事件取消
document.onmouseup = function () {
document.onmousemove = null;
// 将鼠标松开事件取消
document.onmouseup = null;
}
// 浏览器会默认对拖拽的内容进行搜索,用return false取消这个默认行为
return false;
}
}
// 给box1开启拖拽
var box1 = document.getElementById("box1");
drag(box1);
}
</script>
</head>
<body>
haha
<div id="box1"></div>
</body>
</html>
三、DOM查询
1.获取元素节点
通过document对象调用
- 通过id名获取一个HTML元素:getElementById()
- 通过标签名获取一组HTML元素:getElementsByTagName(),这个方法会返回一个类数组对象,所有查询到的元素都会封装到该对象中。
- 通过name属性获取一组HTML元素:getElementByName()
- 通过class属性获取一组HTML元素:getElementByClassName(),该方法不支持ie8及以下的浏览器
练习
图片切换
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#wrapper {
width: 500px;
height: 400px;
margin: 50px auto;
text-align: center;
}
#wrapper img {
width: 500px;
height: 400px;
}
</style>
<script>
// window.onload事件可以使js代码在DOM树加载完成后再执行
window.onload = function () {
// 创建一个数组存储所有图片
var imgArr = ["./imgs/1.jpg", "./imgs/2.jpg", "./imgs/3.jpg", "./imgs/4.jpg", "./imgs/5.jpg"];
// 创建一个变量表示当前显示的图片的索引
var index = 0;
//获取到两个按钮对象
var prev = document.getElementById("prev");
var next = document.getElementById("next");
// 获取到图片对象
var img = document.getElementsByTagName("img")[0];
// 获取到p元素
var info = document.getElementById("info");
//设置提示信息
info.innerHTML = "共" + imgArr.length + "张," + "第" + (index + 1) + "张";
// 分别为两个按钮绑定单击响应函数
prev.onclick = function () {
// 当点击 上一张 按钮时,图片索引减1
index--;
// 如果index小于0,将其修改为最后一张的索引
if (index < 0) {
index = imgArr.length - 1;
}
// 将img的src属性改为修改后的索引
img.src = imgArr[index];
// 点击 上一张 按钮后,修改提示信息
info.innerHTML = "共" + imgArr.length + "张," + "第" + (index + 1) + "张";
}
next.onclick = function () {
// 当点击 下一张 按钮时,图片索引增加1
index++;
// 当index大于最大的索引时,将它改为0,也就是回到第一张
if (index > imgArr.length - 1) {
index = 0;
}
// 将图片的src属性修改为新的索引
img.src = imgArr[index];
// 点击 下一张 按钮后,修改提示信息
info.innerHTML = "共" + imgArr.length + "张," + "第" + (index + 1) + "张";
}
}
</script>
</head>
<body>
<div id="wrapper">
<p id="info"></p>
<img src="./imgs/1.jpg">
<button id="prev">上一张</button>
<button id="next">下一张</button>
</div>
</body>
</html>
2.获取元素节点的子节点
- getElementByTagName()方法,返回元素的子元素
- childNodes属性,返回元素的所有的子节点,包括文本节点
children属性,返回元素的所有子元素 - fristChild属性,返回元素的第一个子节点,包括空白的文本节点
fristElementChild属性,返回元素的第一个子元素(不支持ie8及ie8以下的浏览器) - lastChild属性,返回元素的最后一个子节点,包括空白的文本节点
3.获取元素节点的父节点和兄弟节点
- parentNode,获取节点的父元素
- previousSibling,获取节点的前一个兄弟节点
previousElementSibling,获取节点的前一个兄弟元素(ie8及以下不支持) - nextSibling,获取节点的后一个兄弟节点
练习
全选练习
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
window.onload = function () {
// 获取到所有的项
var sports = document.getElementsByName("sports");
// 获取到全选按钮
var checkall = document.getElementById("checkall");
// 为全选按钮绑定单击响应函数
checkall.onclick = function () {
// 修改四个多选框的checked属性为checked
for (var i = 0; i < sports.length; i++) {
sports[i].checked = true;
}
//修改 全选/全不选 为选中
checkallbox.checked = true;
}
// 获取全不选按钮
var checkno = document.getElementById("checkno");
// 为全不选按钮绑定单击响应函数
checkno.onclick = function () {
// 为四个多选框设置checked为false
for (var i = 0; i < sports.length; i++) {
sports[i].checked = false;
}
//修改 全选/全不选 为不选中
checkallbox.checked = false;
}
// 获取反选按钮
var checkrev = document.getElementById("checkrev");
// 为反选按钮绑定单击响应函数
checkrev.onclick = function(){
// 如果当前遍历到的元素checked属性为true,将其改为false,如果为false,则改为true
for(var i = 0; i<sports.length; i++){
if(sports[i].checked == true){
sports[i].checked = false;
}else{
sports[i].checked = true;
}
}
// 设置checkallbox默认被选中
checkallbox.checked = true;
// 判断四个多选框是否被全部选中
for(var j=0; j<sports.length; j++){
if(sports[j].checked == false){
checkallbox.checked = false;
}
}
}
// 获取提交按钮
var submit = document.getElementById("submit");
// 为提交按钮绑定单击响应函数
submit.onclick = function(){
for(var i = 0; i<sports.length; i++){
// 如果当前遍历到的元素 checked 属性为true,则输出它的值
if(sports[i].checked == true){
alert(sports[i].value);
}
}
}
// 获取 全选/全不选 多选框
var checkallbox = document.getElementById("checkallbox");
// 为 全选/全不选 多选框设置单击响应函数
checkallbox.onclick = function(){
for(var i = 0; i<sports.length; i++){
// sports[i].checked = checkallbox.checked;
sports[i].checked = this.checked;
}
}
// 为四个多选框设置单击响应函数
for(var i=0; i<sports.length; i++){
sports[i].onclick = function(){
checkallbox.checked = true;
for(var j=0; j<sports.length; j++){
if(sports[j].checked == false){
checkallbox.checked = false;
}
}
}
}
}
</script>
</head>
<body>
你爱好的运动是?
<input type="checkbox" id="checkallbox">全选/全不选
<br><br>
<input type="checkbox" name="sports" value="足球"> 足球
<input type="checkbox" name="sports" value="篮球"> 篮球
<input type="checkbox" name="sports" value="羽毛球"> 羽毛球
<input type="checkbox" name="sports" value="乒乓球"> 乒乓球
<br><br>
<input type="button" id="checkall" value="全选">
<input type="button" id="checkno" value="全不选">
<input type="button" id="checkrev" value="反选">
<input type="button" id="submit" value="提交">
</body>
</html>
4.获取几个特定的元素
- document.body:获取body标签
- document.documentElement:获取html标签
- document.all:获取页面中所有元素
5.根据CSS选择器获取元素
querySelector()
- 接受一个选择器字符串作为参数,根据选择器来查询一个元素
- 该方法只会返回第一个符合条件的元素
querySelectorAll()
- 接受一个选择器字符串作为参数,根据选择器来查询一组元素
- 该方法会将所有符合条件的元素放入一个类数组对象返回
四、DOM增删改
- document.createElement():用于创建一个元素节点对象,需要一个标签名作为参数,根据该参数创建元素,并将创建好的节点作为返回值返回。
- document.createTextNode():用于创建一个文本节点对象,需要一个文本内容作为参数,根据该参数创建文本节点,并将创建好的节点作为返回值返回。
- appendChild():向一个父节点中添加一个新的子节点
- insertBefore():在指定子节点之前插入新的节点(父元素调用)
- replaceChild():替换指定的子节点
- removeChild():删除指定的子节点
练习
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#info {
border: 1px solid #000;
border-collapse: collapse;
width: 400px;
}
#info td,
#info th {
border: 1px solid #000;
}
#insert {
text-align: center;
}
</style>
<script>
// 删除tr的响应函数
function delTr(){
// 获取到当前点击的a对应的tr
var tr = this.parentNode.parentNode;
// 获取到当前点击的a对应的名字
// children 返回元素的所有子元素
var name = tr.children[0].innerHTML;
if(confirm("确认删除"+name+"吗")){
tr.parentNode.removeChild(tr);
}
}
window.onload = function () {
/* 删除信息 */
// 获取超链接
var allA = document.getElementsByTagName("a");
// 为每个超链接绑定单击响应函数
for (var i = 0; i < allA.length; i++) {
allA2[i].onclick = delTr;
}
/* 添加信息 */
// 获取提交按钮
var submit = document.getElementById("submit");
// 为提交按钮绑定单击响应函数
submit.onclick = function () {
// 获取用户输入的值
var name = document.getElementsByName("name")[0].value;
var email = document.getElementsByName("email")[0].value;
var salary = document.getElementsByName("salary")[0].value;
// 创建一个tr
var tr = document.createElement("tr");
// 创建四个td
var nameTd = document.createElement("td");
var emailTd = document.createElement("td");
var salaryTd = document.createElement("td");
var aTd = document.createElement("td");
// 创建td中的a
var a = document.createElement("a");
// 创建td中的文本节点
var nameText = document.createTextNode(name);
var emailText = document.createTextNode(email);
var salaryText = document.createTextNode(salary);
// 创建a中的文本节点
var aText = document.createTextNode("Delete");
// 将获取到的信息添加到新建的td中
nameTd.appendChild(nameText);
emailTd.appendChild(emailText);
salaryTd.appendChild(salaryText);
// 将a中的文本添加到a中
a.appendChild(aText);
// 将a添加到td中
aTd.appendChild(a);
// 将创建好的新的td添加到新的tr中
tr.appendChild(nameTd);
tr.appendChild(emailTd);
tr.appendChild(salaryTd);
tr.appendChild(aTd);
// 设置a的href属性
a.href = "javascript:;";
// 获取表格对象
var infoTable = document.getElementById("info");
// 将tr添加到表格中
// 在内存中,表格中的内容实际上是在tbody中的
var tbody = infoTable.getElementsByTagName("tbody")[0];
tbody.appendChild(tr);
// 为新创建的a添加单击响应函数
var allA2 = document.getElementsByTagName("a");
for (var i = 0; i < allA.length; i++) {
allA2[i].onclick = delTr;
}
}
};
</script>
</head>
<body>
<table id="info">
<tr>
<th>Name</th>
<th>Email</th>
<th>Salary</th>
<th> </th>
</tr>
<tr>
<td>Tom</td>
<td>tom@163.com</td>
<td>5000</td>
<td><a href="javascript:;">Delete</a></td>
</tr>
<tr>
<td>Jerry</td>
<td>Jerry@163.com</td>
<td>8000</td>
<td><a href="javascript:;">Delete</a></td>
</tr>
</table>
<br><br>
<table id="insert">
<tr>
<th>添加新员工</th>
</tr>
<tr>
<td>name:<input type="text" name="name"></td>
</tr>
<tr>
<td>email:<input type="text" name="email"></td>
</tr>
<tr>
<td>salary:<input type="text" name="salary"></td>
</tr>
<tr>
<td><button id="submit">提交</button></td>
</tr>
</table>
</body>
</html>
优化
// 删除tr的响应函数
function delTr(){
// 获取到当前点击的a对应的tr
var tr = this.parentNode.parentNode;
// 获取到当前点击的a对应的名字
// children 返回元素的所有子元素
var name = tr.children[0].innerHTML;
if(confirm("确认删除"+name+"吗")){
tr.parentNode.removeChild(tr);
}
}
window.onload = function () {
// 获取超链接
var allA = document.getElementsByTagName("a");
// 为每个超链接绑定单击响应函数
for (var i = 0; i < allA.length; i++) {
allA[i].onclick = delTr;
}
/* 添加信息 */
// 获取提交按钮
var submit = document.getElementById("submit");
// 为提交按钮绑定单击响应函数
submit.onclick = function () {
// 获取用户输入的值
var name = document.getElementsByName("name")[0].value;
var email = document.getElementsByName("email")[0].value;
var salary = document.getElementsByName("salary")[0].value;
// 创建一个tr
var tr = document.createElement("tr");
/* 优化 */
tr.innerHTML = "<td>"+name+"</td>"+
"<td>"+email+"</td>"+
"<td>"+salary+"</td>"+
"<td>"+"<a href='javascript:;'>Delete</a>"+"</td>"
// 获取表格对象
var infoTable = document.getElementById("info");
// 将tr添加到表格中
// 在内存中,表格中的内容实际上是在tbody中的
var tbody = infoTable.getElementsByTagName("tbody")[0];
tbody.appendChild(tr);
// 为新创建的a添加单击响应函数
var allA2 = document.getElementsByTagName("a");
for (var i = 0; i < allA.length; i++) {
allA2[i].onclick = delTr;
}
}
};
五、使用DOM操作CSS
JS是通过style属性对CSS样式进行操作的,通过style属性设置的样式优先级较高,所以一般情况下JS设置的样式都能够立即生效。
1.设置CSS样式
语法:元素.style.样式名 = “样式值”;
注意:在JS中,带有-的属性名是不合法的,遇到之后将其改为驼峰命名法,比如background-color,改为backgroundColor。
2.读取CSS样式
(1)元素.style.样式名:读取内联样式
<style>
#box1 {
width: 200px;
height: 200px;
background-color: coral;
}
</style>
<script>
window.onload = function () {
// 获取box1
var box1 = document.getElementById("box1");
// 获取按钮
var btn01 = document.getElementById("btn");
// 点击按钮时修改box1的宽度
btn.onclick = function(){
box1.style.width = "300px";
}
}
</script>
<button id="btn">点击</button>
<br><br>
<div id="box1"></div>
(2)元素.currentStyle.样式名:读取当前正在显示的样式(只支持ie)
(3)getComputedStyle()方法:读取元素当前显示的样式(ie8及以下不支持)
- 该方法是window的方法,可以直接使用
- 两个参数:第一个->要获取样式的元素
第二个:可以传递一个伪元素,一般都传null - 该方法会返回一个对象,对象中封装了当前元素所有的样式
注意: currentStyle属性和getComputedStyle()方法获取到的样式都是只读的,想要修改必须通过style属性。
兼容所有浏览器的方案
<style>
#box1 {
width: 200px;
height: 200px;
background-color: coral;
}
</style>
<script>
//创建一个getStyle()方法
//obj:指要获取样式的元素
//propertyName:指要获取该元素的样式名
function getStyle(obj,propertyName){
// 如果是正常浏览器,就会具有getComputedStyle()方法
if(window.getComputedStyle){
// 使用getComputedStyle()方法返回元素当前的样式
return getComputedStyle(obj,null)[propertyName];
}else{
// 如果是ie8及以下浏览器,就使用currentStyle属性返回当前元素的样式
return obj.currentStyle[propertyName];
}
}
//获取box1的backgroundColor
var result = getStyle(box1,"backgroundColor");
alert(result); //rgb(255, 127, 80)
</script>
<div id="box1"></div>