一. 什么是DOM: Document Object Model
1. 什么是: 专门操作网页内容的一套对象和函数的总称
2. 为什么: ES标准中只规定了js语言的核心语法。没有规定如何使用js操作网页的内容。
3. 何时: 今后,只要想操作网页中的内容时,只能用DOM
4. DOM标准: 国际标准,由W3C负责制定并维护。
几乎所有浏览器100%兼容
5. 包括: 5件事: 增删改查+事件绑定
二. DOM树:
1. 什么是: 一个网页的所有内容,在浏览器内存中,以树形结构保存的
2. 为什么: 树形结构是最直观的展现上下级包含关系的结构。而网页内容中的元素结构,也是上下级包含关系。
3. 如何:
(1). 只要浏览器读取到一个网页的内容,都会先在内存中创建一个唯一的树根节点对象: document
(2). 浏览器扫描网页内容,每扫描到一项内容(元素、文本、属性...),就会自动创建一个新的节点对象(Node),保存当前这一项内容的属性和值。然后将新创建的节点对象,保存到DOM树上对应的位置。
三. 查找元素: 4大类查找方式
1. 不需要查找,就可直接获得元素/对象: 4个
(1). 根节点对象: document
(2). html元素节点对象: document.documentElement
(3). head元素节点对象: document.head
(4). body元素节点对象: document.body
2. 按节点间关系查找
(1). 什么是:按照元素在DOM树中的上下级或平级关系查找其它元素
(2). 何时: 如果已经获得一个DOM元素对象,想找这个DOM元素对象周围附近的元素时,才用节点间关系。
(3). 如何:
a. 节点树:
1). 什么是: 包含所有网页内容的完整树结构
2). 包含: 2大类关系,6个属性
i. . 父子关系: 4个属性
获得一个节点对象的父级节点对象
节点对象.parentNode —— 返回一个节点对象
父 节点
获得一个节点对象下的所有直接子节点对象的集合
节点对象.childNodes —— 返回类数组对象
子 节点们
获得一个节点对象下的第一个直接子节点对象
节点对象.firstChild —— 返回一个节点对象
第一个 孩子
获得一个节点对象下的最后一个直接子节点对象
节点对象.lastChild —— 返回一个节点对象
最后一个 孩子
ii. 兄弟关系: 2个属性
获得一个节点对象相邻的前一个兄弟节点对象
节点对象.previousSibling
前一个 兄弟
获得一个节点对象相邻的下一个兄弟节点对象
节点对象.nextSibling
下一个 兄弟
3). 问题: 节点树会将看不见的回车、空格等空字符也创建为节点对象。严重干扰我们的查找结果!所以,今后几乎不用节点树。
b. 元素树:
1). 什么是: 仅包含元素节点的树形结构
2). 优点: 不会受到看不见的空字符的干扰!所以,将来只要按节点间关系查找元素时,都用元素树
3). 包含: 2大类关系,6个属性
i. . 父子关系: 4个属性
获得一个元素对象的父级元素对象
元素对象.parentElement —— 返回一个元素对象
父 元素
获得一个元素对象下的所有直接子元素对象的集合
元素对象.children —— 返回类数组对象
孩子们
获得一个元素对象下的第一个直接子元素对象
元素对象.firstElementChild —— 返回一个元素对象
第一个 元素 孩子
获得一个元素对象下的最后一个直接子元素对象
元素对象.lastElementChild —— 返回一个元素对象
最后一个 元素 孩子
ii. 兄弟关系: 2个属性
获得一个元素对象相邻的前一个兄弟元素对象
元素对象.previousElementSibling
前一个 元素 兄弟
获得一个元素对象相邻的下一个兄弟元素对象
元素对象.nextElementSibling
下一个 元素 兄弟
(4). 示例: 输出指定元素,并用节点间关系查找想要的元素
1_domTree.html
<!DOCTYPE HTML>
<html>
<head>
<title>DOM Tree</title>
<meta charset="utf-8" />
</head>
<body>
<span id="s1">Hello</span>
<h1>标题一</h1>
<script>
//先获得四种可直接获得的节点对象
//DOM中: console.log输出的不是对象存储结构,而是DOM树结构(节点间关系)
console.log(document);
console.log(document.documentElement);
console.log(document.head);
console.log(document.body);
//console.dir(xxx)才是输出一个节点对象在内存中的属性结构
console.dir(document);
console.dir(document.documentElement);
console.dir(document.head);
console.dir(document.body);
//获得body的第一个直接子元素span
// var span=document.body.firstChild
var span=document.body.firstElementChild;
console.log(span);
//获得span的下一个兄弟h1
// var h1=span.nextSibling;
var h1=span.nextElementSibling;
console.log(h1);
//获得body下所有直接子元素的集合:3个元素
// console.log(document.body.childNodes);
console.log(document.body.children);
</script>
</body>
</html>
运行结果:
3. 按HTML特征查找: 4个函数
(1). 按id名查找一个元素:
a. var 一个元素对象=document.getElementById("id名")
b. 意为 在整个页面中 通过id名
查找元素
c. 返回值:
1). 如果找到符合要求的元素,则只返回一个元素对象
2). 如果没找到,则返回null
d. 强调:
1). .前的主语必须是document
2). 因为只找一个元素,所以函数名中Element没有s结尾,是单数形式。
(2). 按标签名查找多个元素:
a. var 类数组对象=任意父元素.getElementsByTagName("标签名")
b. 意为: 在指定父元素范围内 通过标签名
获取多个元素
c. 返回值:
1). 如果找到符合要求的元素,就返回类数组对象
2). 如果没找到,返回空类数组对象: { length:0 }
d. 强调:
1). 因为找到多个元素,所以返回值为类数组对象
2). 最好指定只在一个父元素范围内查找符合要求的元素。——优化,查找范围越小,查找越快!
3). 因为找到多个元素,所以函数名中的Elements以s结尾,表示复数
4). 不仅查找直接子元素,而且会在所有后代元素中查找符合要求的元素。
5). 如果这个函数规定要返回类数组对象,那么在任何时候,都会返回类数组对象!即使只找到一个元素,也会把这唯一的一个元素放在类数组对象中第一个位置返回。所以,如果只找到一个符合要求的元素时,必须用[0],取出类数组对象中第一个位置保存的元素对象,才能对这个元素对象继续执行后续操作!
(3). 按class名查找多个元素:
a. var 类数组对象=任意父元素.getElementsByClassName("class名")
b. 意为: 在指定父元素范围内 通过class名
获取多个元素
c. 返回值:
1). 如果找到符合要求的元素,就返回类数组对象
2). 如果没找到,返回空类数组对象: { length:0 }
d. 强调:
1). 因为找到多个元素,所以返回值为类数组对象
2). 最好指定只在一个父元素范围内查找符合要求的元素。——优化,查找范围越小,查找越快!
3). 因为找到多个元素,所以函数名中的Elements以s结尾,表示复数
4). 不仅查找直接子元素,而且会在所有后代元素中查找符合要求的元素。
5). 如果这个函数规定要返回类数组对象,那么在任何时候,都会返回类数组对象!即使只找到一个元素,也会把这唯一的一个元素放在类数组对象中第一个位置返回。所以,如果只找到一个符合要求的元素时,必须用[0],取出类数组对象中第一个位置保存的元素对象,才能对这个元素对象继续执行后续操作!
(4). 按name名查找多个表单元素:
a. var 类数组对象=document.getElementsByName("name名")
b 意为: 在整个页面范围内 通过name名
获取多个元素
c. 返回值:
1). 如果找到符合要求的元素,就返回类数组对象
2). 如果没找到,返回空类数组对象: { length:0 }
d. 强调:
1). .前必须是document,不能改为其它任意元素
2). 因为可能找到多个,所以也返回类数组对象
3). 因为可能找到多个,函数名中的Elements也是s结尾,表示复数
4). 如果这个函数规定要返回类数组对象,那么在任何时候,都会返回类数组对象!即使只找到一个元素,也会把这唯一的一个元素放在类数组对象中第一个位置返回。所以,如果只找到一个符合要求的元素时,必须用[0],取出类数组对象中第一个位置保存的元素对象,才能对这个元素对象继续执行后续操作!
(5). 示例: 查找指定的元素,并修改元素的样式:
2_getElements.html
<!DOCTYPE HTML>
<html>
<head>
<title>遍历节点树</title>
<meta charset="utf-8"/>
</head>
<body>
<span>Hello World !</span>
<ul id="nav">
<li class="item parent">电影</li>
<li class="item parent">综艺
<ul>
<li class="item child active">跑男</li>
<li class="item child">爸爸</li>
<li class="item child">极限</li>
</ul>
</li>
<li class="item parent">剧集</li>
</ul>
<form>
用户名:<input name="uname"><br/>
性别:<label><input type="radio" name="sex" value="1">男</label>
<label><input type="radio" name="sex" value="0">女</label>
</form>
<script>
//查找id为nav的一个ul元素
var ulNav=document.getElementById("nav");
console.log(ulNav);
//在id为nav的ul下查找所有li
var lis=ulNav.getElementsByTagName("li");
console.log(lis);
//在id为nav的ul下查找tr
var trs=ulNav.getElementsByTagName("tr");
console.log(trs);
//在body下查找span元素
var span=document.body.getElementsByTagName("span")[0];//从查找结果的类数组对象中取出保存在第一个位置的唯一一个DOM元素对象。
console.log(span);
span.style.color="red";
//查找id为nav的ul下的所有class为item的元素
var items=ulNav.getElementsByClassName("item");
console.log(items);
//查找id为nav的ul下的class为active的一个li,修改其字体颜色为红色
var li=ulNav.getElementsByClassName("active")[0];//取出查找结果的类数组对象中保存在第一个位置的唯一一个DOM元素对象
console.log(li);
li.style.color="red";
//查找name为sex的两个radio元素
var radios=document.getElementsByName("sex");
console.log(radios);
//查找一个name为uname的元素,为其添加阴影效果
var 姓名文本框=document.getElementsByName("uname")[0];
console.log(姓名文本框);
姓名文本框.style.boxShadow="0 0 5px red";
</script>
</body>
</html>
运行结果:
四. 购物车:
1. 所有DOM效果标准4步
(1). 查找所有可能触发事件的元素
(2). 绑定事件处理函数
(3). 查找要修改的元素
(4). 修改元素
2. 回顾: 事件绑定:
(1). 什么是事件: 浏览器自动触发的或用户手动触发的页面中内容或状态的变化
(2). 问题: 默认,即使浏览器中发生了事件,浏览器什么也不会做!
(3). 解决: 绑定事件处理函数: 2种
a. 手工在html中元素开始标签中绑定事件处理函数
<元素 on事件名="事件处理函数()">
<script>
function 事件处理函数(){ ... }
缺点: 全手工添加,极其不便于维护!——几乎不用
b. 在js中绑定:
1). 其实,每个元素对象身上,都长着一批名称以on开头的"事件属性"
比如: onclick, onfocus, onmouseover,...
2). 当一个元素身上发生了一个事件时,浏览器会先在这个元素身上找到对应的事件属性,并执行事件属性中保存的事件处理函数。
3). 问题: 开局,所有元素的事件属性都为null,即使发生事件,也不知道该干什么
4). 解决: 事件绑定:
i. 什么是: 提前在元素的某个事件属性上保存一个function函数。当事件发生时,浏览器就可以找到这个函数,并自动执行!
ii. 何时: 只要希望触发事件时,可以自动执行一项提前定义好的操作时,都要先为元素绑定事件处理函数.
iii. 如何: js中
先找到要触发事件的元素
元素对象.on事件名=function(){ ... }
5). 优点: 自动绑定,可以与for循环配合批量绑定,集中绑定。
(4). 问题: 在事件处理函数中,想获得当前触发事件的元素本身。如果用事件处理函数以外的其它变量,都不靠谱。
(5). 解决: 今后,只要在DOM的事件处理函数中,想获得当前触发事件的元素本身,都要用this
this->正在触发事件的当前元素本身。
(5). 示例: 为table下所有按钮提前绑定单击事件处理函数
3_shoppingCart.html
<!DOCTYPE HTML>
<html>
<head>
<title>使用Selector API实现购物车客户端计算</title>
<meta charset="utf-8" />
<style>
table {
width: 600px;
text-align: center;
border-collapse: collapse;
}
td,
th {
border: 1px solid black
}
td[colspan="3"] {
text-align: right;
}
</style>
</head>
<body>
<table id="data">
<thead>
<tr>
<th>商品名称</th>
<th>单价</th>
<th>数量</th>
<th>小计</th>
</tr>
</thead>
<tbody>
<tr>
<td>iPhone6</td>
<td>¥4488.00</td>
<td>
<button>-</button>
<span>1</span>
<button>+</button>
</td>
<td>¥4488.00</td>
</tr>
<tr>
<td>iPhone6 plus</td>
<td>¥5288.00</td>
<td>
<button>-</button>
<span>1</span>
<button>+</button>
</td>
<td>¥5288.00</td>
</tr>
<tr>
<td>iPad Air 2</td>
<td>¥4288.00</td>
<td>
<button>-</button>
<span>1</span>
<button>+</button>
</td>
<td>¥4288.00</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">Total: </td>
<td>¥14064.00</td>
</tr>
</tfoot>
</table>
<script>
//1. 查找触发事件的元素
//本例中: 在table下查找所有button元素
//1.1 先查找id为data的table元素
var table=document.getElementById("data");
//1.2 在table中查找所有button元素
var 按钮们=table.getElementsByTagName("button");
console.log(按钮们);
//2. 绑定事件处理函数
//本例中: 为找到的每个按钮都绑定单击事件处理函数
//所以遍历查找结果中每个DOM元素按钮
for(var 按钮 of 按钮们){
console.dir(按钮);
按钮.onclick=function(){
//点那个按钮,就让当前按钮的内容变成一朵小花
//错误: 始终改最后一个按钮
// 按钮.innerHTML="❀";
//正确: 修改当前触发事件的按钮本身
this.innerHTML="❀";
}
}
</script>
</body>
</html>
运行结果: