46-2 JavaScript的对象-host object-DOM
DOM(文档对象模型,Document Object Model) 定义了访问 HTML 和 XML 文档的标准,允许程序和脚本动态地访问和更新文档的内容、结构和样式。
DOM 是 W3C(万维网联盟)的标准。分为 3 个不同的部分:
- 核心 DOM: 针对任何结构化文档的标准模型
- XML DOM: 针对 XML 文档的标准模型,定义了所有 XML 元素的对象和它的属性、方法。
- HTML DOM: 针对 HTML 文档的标准模型,定义了所有 HTML 元素的对象和它的属性、方法。
本文讲的是HTML DOM。对谁、在何时、做什么样的操作。
一、对谁操作
(一)DOM节点
根据 W3C 的 HTML DOM 标准,HTML 文档中的所有内容都是节点(node):
- 整个文档是一个文档节点 : document对象
- 每个 HTML 元素(即标签)是元素节点 : element 对象
- HTML 元素内的文本是文本节点 : text对象
- 每个 HTML 属性是属性节点 : attribute对象
- 注释是注释节点 : comment对象
每个节点都有自己的“自身属性”和“导航属性”。节点中最常用的是Document节点对象和Element节点对象。

1、自身属性
- nodeName : 节点名称
- nodeType : 节点类型
- nodeValue : 节点值
- attributes : 节点(元素)的属性节点
- innerHTML : 节点(元素)内部的文本
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<div id="div1">
<div>hello div</div>
<p>hello p</p>
</div>
</div>
<script>
var ele=document.getElementById("div1");
console.log(ele.nodeName); // DIV 标签名字
console.log(ele.nodeType); // 1 编号,代表类型号
console.log(ele.nodeValue); // null
console.log(ele.attributes); // NamedNodeMap {0: id, length: 1}
</script>
</body>
</html>
2、导航属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div1">
<div>hello div</div>
<a herf="#">hello a</a>
<p>hello p</p>
</div>
</body>
</html>
以上document的文档树:

节点树中的节点彼此拥有层级关系:
-
- 在节点树中,顶端节点被称为根(root)
- 除了根,每个节点都有父节点(parent)
- 一个父节点可拥有任意数量的子节点(child)
- 同级的子节点被称为同胞、兄弟或姐妹(sibling)
(二)获取对象
1、通过导航属性获取节点对象:
<script>
var ele_obj=document.getElementById("div1");
console.log(ele_obj.nodeName); // DIV
// 方式一:所有node都拿
console.log(ele_obj.parentNode.nodeName); // BODY
console.log(ele_obj.firstChild.nodeName); // #text div2前有一个换行符,还有个缩进,它们属于text节点对象
console.log(ele_obj.firstChild.nextSibling.nodeName); // DIV
console.log(ele_obj.lastChild.nodeName); // #text
console.log(ele_obj.lastChild.previousSibling.nodeName); // P
console.log(ele_obj.childNodes); // [text, div, text, a, text, p, text]
// 方式二:只拿element(标签)对象。推荐使用的方式
console.log(ele_obj.parentNode.nodeName); // BODY
console.log(ele_obj.firstElementChild.nodeName); // DIV
console.log(ele_obj.firstElementChild.nextElementSibling.nodeName); // A
console.log(ele_obj.lastElementChild.nodeName); // P
console.log(ele_obj.lastElementChild.previousElementSibling.nodeName); // A
console.log(ele_obj.children); // [div, a, p]
</script>
2、通过对象的方法获取节点对象
(1)全局查找:document下查找
document.getElementById() document.getElementsByTagName() // 获取到的是一个数组 document.getElementsByClassName() // 获取到的是一个数组 document.getElementsByName() // 获取到的是一个数组
(2)局部查找:在某一标签对象下查找
ele_obj.getElementsByTagName() // 获取到的是一个数组 ele_obj.getElementsByClassName() // 获取到的是一个数组
二、在何时操作—— DOM 事件
当用户点击某个 HTML 元素时启动一段 JavaScript代码。
1、给元素添加事件
(1)方式一:直接写在标签上(注意函数名后加括号才表示执行)
<div id="div1" onclick="alert(123)">点我呀</div>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p id="p1" onclick="func1(this)">hellop</p> </body> <script> function func1(self){ alert(self.innerHTML); } </script> </html>
(2)方式二:在js区域,先找到标签对象,再对其进行事件绑定
var ele=document.getElementById("div1");
ele.onclick=function(){
alert("123");
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p id="p1">hellop</p> </body> <script> var ele=document.getElementById("p1"); ele.onclick=function(){ alert(this.innerHTML); } </script> </html>
2、各种事件属性的介绍:
- onclick 用户点击某个对象时
- ondblclick 用户双击某个对象时
- onfocus 元素获得焦点时
- onblur 元素失去焦点时
- onchange 域的内容被改变时
- onselect 文本被选中时
- onsubmit 确认按钮被点击时
- onload 一张页面或一幅图像完成加载时
- onmousedown 鼠标按钮被按下时
- onmousemove 鼠标被移动时
- onmouseover 鼠标移到某元素之上时
- onmouseout 鼠标从某元素移开时
- onmouseleave 鼠标从元素离开时
- onkeydown 某个键盘按键被按下时
- onkeyup 某个键盘按键被松开时
- onkeypress 某个键盘按键被按下并松开
(1)onfocus、onblur
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input class="vip_no" type="text" onfocus="func1()" onblur="func2()" value="请输入卡号"> <input type="text" value="请输入卡号"> <!--获取焦点后,值不能自动消失,失去焦点后值不自动出现--> <input type="text" placeholder="请输入卡号"> <!--在用户输入空格后,失去焦点提示不出现--> <script> function func1(){ var ele=document.getElementsByClassName("vip_no")[0]; ele.value=""; } function func2(){ var ele=document.getElementsByClassName("vip_no")[0]; if (ele.value.trim().length==0){ // 判断用户是否输入空或仅为空格 ele.value="请输入卡号"; // 如果未有效输入,则重现提示 } } </script> </body> </html>
(2)onchange
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<select onchange="func3()" >
<option>上海</option>
<option>北京</option>
<option>广州</option>
</select>
<script>
function func3(){
alert(1234);
}
</script>
</body>
</html>
(3)onsubmit
用于form标签的提交验证。
a. 通过 return false 阻止表达提交
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--注意:加return关键字,因为onsubmit需要一个布尔值。而函数返回的结果是字符串,并不是真正的布尔值--> <form id="form1" onsubmit="return check()"> <input type="text" name="username"> <input type="submit" value="submit"> </form> <script> function check(){ alert("验证失败!"); return false; // 当onsubmit得到false后,阻止提交并且知道先不要清空输入框中的内容,以便用户纠正已输入的内容而不是重新输 } </script> </body> </html>
b. 通过 event.preventDefault() 阻止表达提交
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form id="form1"> <input type="text" name="username"> <input type="submit" value="submit"> </form> <script> var Form=document.getElementById("form1"); Form.onsubmit=function(event){ // event参数可以省略不写 alert("验证失败"); // return false // 阻止方式一(与上面的例子在函数中返回false道理一样) event.preventDefault(); // 阻止方式二 }; </script> </body> </html>
关于event对象:
event对象在事件发生时系统已经创建好了,并且会在事件函数被调用时传给事件函数。我们获得仅仅需要接收一下即可。
Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
(4)onmouseover、onmousedown、onmousemove、onmouseout
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> div{ height: 100px; background-color: green; width:200px; } </style> </head> <body> <div onmouseover="over()" onmousedown="down()" onmousemove="move()" onmouseout="out()" >div1</div> </body> <script> function over(){ console.log("over"); } function down(){ console.log("down"); } function move(){ console.log("move"); } function out(){ console.log("out"); } </script> </html>
(5)onload
定义代码一加载完就触发的事件。
使用场景1:当script代码放在html文档头部时,script中可能有操作html标签对象的部分,而此时所有html标签对象还没有加载呢,所以会报错。正确的做法是等加载完整个文档后,再执行这些代码。(另一种方法是:script代码放在文档后部,执行script代码时,html标签对象在上面都已经加载了)
a. 方式一:对windows对象设置onload事件(常用)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script> // 对 window对象设置onload事件:执行function函数时,整个文档都已经加载完成了,所以function函数能正常工作 window.onload=function(){ // 文档加载完时,立马触发执行function函数 var p=document.getElementById("id1"); alert(p.nodeName) } </script> </head> <body> <p id="id1">hello p</p> </body> </html>
b. 方式二:对body设置onload事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script> function func1(){ var p=document.getElementById("id1"); alert(p.nodeName) } </script> </head> <!--对 body设置 onload事件: 执行func1函数时,body里面所有的标签对象都已经加载完成了,所以func1可正常执行--> <body onload="func1()"> <!--body加载完成,立马执行func1函数--> <p id="id1">hello p</p> </body> </html>
(6)onkeydown、onkeyup、onkeypress
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="press" onkeydown="func1(event)" onkeyup="func2(event)"> <input type="button" value="press2" onkeypress="func3(event)"> <script> function func1(e){ console.log(e.keyCode); // 按键的数字编码 } function func2(e){ console.log(456); } function func3(e){ console.log(789); } </script> </body> </html>
3、事件传播
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--所谓事件传播,就是点击div2后,先alert出div2,还要再alert出div1--> <div id="div1" style="background-color:green;width:300px;height:300px;"> <div id="div2" style="background-color: red;width:200px;height:200px;"></div> </div> <script type="text/javascript"> document.getElementById("div1").onclick=function(){ alert('div1'); }; document.getElementById("div2").onclick=function(event){ alert('div2'); event.stopPropagation(); // 阻止事件向外层div传播. } </script> </body> </html>
4、事件委托
$("要绑定的标签的上级").on("click", "要绑定的标签", function(){})
好处:
1、省内存
2、子代可能还未出生,所以无法对其直接绑定事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table border="1px"> <tbody id="tb"> <tr> <td>111</td> <td class="del-row">删除</td> </tr> <tr> <td>222</td> <td class="del-row">删除</td> </tr> <tr> <td>333</td> <td class="del-row">删除</td> </tr> <tr> <td>444</td> <td class="del-row">删除</td> </tr> </tbody> </table> </body> <script src="jquery-3.2.1.js"></script> <script> /*将事件绑定在父辈或以上*/ $("#tb").on("click", ".del-row", function(){ $(this).parent().remove(); }) </script> </html>
5、补充
(1)this
可很方便的根据点击确定操作对象。两种事件绑定方法下this的使用:
a、在html标签上直接绑定事件时:要将this传给函数,函数中使用的this才是本标签
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="div" onclick="func1(this)">hello</div> <!--将this作为实参传给函数--> <div id="div" onclick="func2()">hello2</div> <!--没有给函数传this参数--> <script> function func1(arg){ console.log(arg); // 接收到的this代指的是本标签 //打印的结果为:<div id="div" onclick="func1(this)">hello</div> } function func2(){ console.log(this); // 直接在函数中调用this,this代指window //打印结果Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} } </script> </body> </html>
b、在script代码中绑定事件时:直接在函数中用this即可,this代指本标签
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="div">hello</div> <script> document.getElementById("div").onclick=function() { console.log(this); // 直接使用this,this代指本标签 // 打印结果为:<div id="div">hello</div> } </script> </body> </html>
(2)用a标签做伪协议--类似于onclick事件触发
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--<a href="javascript:void(0)">hello</a>--> <!--url不变,不同于加#--> <a href="javascript:show()">hello</a> <!--类似于onclick功能了。伪协议--> <script> function show(){ alert(123); return 66; } </script> </body> </html>
三、做什么样的操作——对node对象的增删改
1、增加
createElement(ele_name); // 先创建元素 parent_ele.appendChild(ele); // 再将元素添加
2、删除
parent_ele.removeChild(ele);
3、更新
即替换,删除旧的,原位置再添加进一个新的。
parent_ele.replaceChild(ele2, ele1) // ele2:新元素 ele1:待替换元素
4、修改
(1)修改元素的属性
ele.getAttribute(att); // 查看ele元素的att属性,如:ele.getAttribute("id")
ele.setAttribute(att, value); // 修改ele元素的att属性, value:对该属性的重新赋值
(2)修改元素的内容
ele.innerHTML=value;
(3)修改元素的样式
// 直接改 ele.style.fontsize="30px"; // 通过类的样式改 ele.className // 一个数组。ele属于哪些类(一般不同的类应用了不同的样式) ele.classList.add(class_name) // 在ele的class属性中,添加到一个名为class_name的新类 ele.classList.remove(class_name) // 在els的class属性中,移除一个名为class_name的新类
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div_1" style="background-color: green;width:200px;height:200px;">hello div1</div>
<div id="div_2" style="background-color: red;width:200px;height:200px;">hello div2</div>
<div id="div_3" style="background-color: dodgerblue;width:200px;height:200px;">hello div3</div>
<div id="div_4" style="background-color: yellow;width:200px;height:200px;">hello div4</div>
<input type="button" value="addNode" onclick="addNode()">
<input type="button" value="deleteNode" onclick="deleteNode()">
<input type="button" value="updateNode" onclick="updateNode()">
<input type="button" value="copyNode" onclick="copyNode()">
<script type="text/javascript">
//添加:在第一个div中动态增加一个a标签. 该a标签点击之后跳转到百度首页.
function addNode(){
var div = document.getElementById("div_1"); // 1.获得 第一个div
var eleA = document.createElement("a"); // 2.创建a标签 createElement ==> <a></a>
eleA.setAttribute("href", "http://www.baidu.com"); // 3.为a标签添加属性 <a href="http://www.baidu.com"></a>
eleA.innerHTML = "百度"; // 4.为a标签添加内容 <a href="http://www.baidu.com">百度</a>
div.appendChild(eleA); // 5.将a标签添加到div中
}
//删除:删除第二个div
function deleteNode(){
var div = document.getElementById("div_2"); // 1.获得要删除的div区域
var parent = div.parentNode; // 2.获得父亲
parent.removeChild(div); // 3.由父亲操刀
}
//替换:替换第三个div为一个美女
function updateNode(){
var div = document.getElementById("div_3"); // 1.获得要替换的div区域3
var img = document.createElement("img"); // 2.创建img标签对象<img/>
img.setAttribute("src", "001.JPG"); // 3.添加属性 <img src="001.jpg" />
// img.src="001.jpg"; // Dhtml html写法(动态html:增强html功能,即把繁杂的写法,用简单的写法表达)
var parent = div.parentNode; // 4.获得父节点
parent.replaceChild(img, div); // 5.替换
}
//克隆:将第四个div克隆一份,添加到页面底部
function copyNode(){
var div = document.getElementById("div_4"); // 1.获取要克隆的div
var div_copy = div.cloneNode(true); // 2.克隆 参数为true 那么克隆时克隆所有子元素. false 只克隆自己
var parent = div.parentNode; // 3.获得父亲
parent.appendChild(div_copy); // 4.添加
}
</script>
</body>
</html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .bigger{ font-size: 30px; color: red; } .small{ font-size: 10px; color: red; } </style> </head> <body> <div id="div1">abscdk</div> <input type="button" value="big" onclick="change('bigger')"> <input type="button" value="small" onclick="change('small')"> <script> // function changeBig(){ // var ele=document.getElementById("div1"); // ele.style.fontSize="30px"; // } // // function changeSmall(){ // var ele=document.getElementById("div1"); // ele.style.fontSize="15px"; // } function change(a){ var ele=document.getElementById("div1"); ele.classList.remove('bigger'); // 初始化 ele.classList.remove('small'); // 初始化 ele.classList.add(a); } </script> </body> </html>
应用实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{
margin: 0;
}
#div1{
position: fixed;
height: 2000px;
width: 100%;
background-color: dodgerblue;
z-index: 1000;
}
#div2{
position: fixed;
top: 0;
left: 0;
right:0;
bottom:0;
background-color: lightgray;
opacity: 0.3;
z-index: 1001;
}
#div3{
position: absolute;
top:50%;
left:50%;
height: 200px;
width: 200px;
background-color: yellow;
z-index: 1002;
margin-top:-100px;
margin-left:-100px;
}
.hide{
display: none;
}
</style>
</head>
<body>
<!--模块对话框应用场景:登录界面弹出时,背景变灰,登录完成后背景在变回来-->
<div id="div1">
<input type="button" value="click" onclick="show()">
</div>
<div id="div2" class="div hide"></div>
<div id="div3" class="div hide">
<input type="button" value="cancel" onclick="cancel()">
</div>
<script>
function show(){
var ele=document.getElementsByClassName("div");
for (var i=0;i<ele.length;i++){
ele[i].classList.remove("hide");
}
}
function cancel(){
var ele=document.getElementsByClassName("div");
for (var i=0;i<ele.length;i++){
ele[i].classList.add("hide");
}
}
</script>
</body>
</html>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<select id="province" onchange="func1(this)"></select>
<select id="city"></select>
<script>
data={"河北":["邯郸","廊坊"], "北京":["海淀","朝阳"], "山东":["济南", "青岛"]};
// 动态生成一级
for (var i in data){
var pro=document.getElementById("province");
var optionProvince=document.createElement("option"); // <option></option>
optionProvince.innerHTML=i; // loop1:<option>河北省</option>
pro.appendChild(optionProvince);
}
// 动态生成二级
function func1(self){
var city=document.getElementById("city");
var choice=(self.options[self.selectedIndex]).innerHTML; // 写法2:var choice=self.value;
city.options.length=0; // 先清空 city中的option
for (i in data[choice]) { // 再通过for循环往 city中加入值
var optionCity = document.createElement("option");
optionCity.innerHTML = data[choice][i];
city.appendChild(optionCity);
}
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#box_L, #choice, #box_R{
display: inline-block;
}
</style>
</head>
<body>
<div id="box_L">
<select id="left" multiple size="10">
<option>选项1</option>
<option>选项2</option>
<option>选项3</option>
<option>选项4</option>
<option>选项5</option>
<option>选项6</option>
</select>
</div>
<div id="choice">
<input type="button" value="-->" onclick="add()"><br>
<input type="button" value="==>" onclick="addAll()"><br>
<input type="button" value="<--"><br>
<input type="button" value="<=="><br>
</div>
<div id="box_R">
<select id="right" multiple size="10">
<option>选项7</option>
</select>
</div>
<script>
var right=document.getElementById("right");
var left=document.getElementById("left");
function add(){
var options=left.children;
for (var i=0;i<options.length;i=i+1){
if (options[i].selected==true){
right.appendChild(options[i]); // 注意:option[i]并不是新创建的。等于从左边移到右边了
i=i-1; // 因为left的options已经发生了变化,还是需要从第一个开始,否则会漏
}
}
}
function addAll(){
var options=left.children;
for (var i=0;i<options.length;i=i+1){
right.appendChild(options[i]);
i=i-1;
}
}
</script>
</body>
</html>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button onclick="select('all');">全选</button>
<button onclick="select('cancel');">取消</button>
<button onclick="select('reverse');">反选</button>
<table border="1" id="Table">
<tr>
<td><input type="checkbox"></td>
<td>111</td>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>222</td>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>333</td>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>444</td>
</tr>
</table>
<script>
function select(choice){
var ele=document.getElementById("Table");
var inputs=ele.getElementsByTagName("input");
for (var i=0;i<inputs.length;i=i+1){
var ele2=inputs[i];
if (choice=="all"){
ele2.checked=true;
}else if(choice=="cancel"){
ele2.checked=false;
}
else {
if (ele2.checked){
ele2.checked=false;
}else {
ele2.checked=true;
}
}
}
}
</script>
</body>
</html>

参考:
http://www.cnblogs.com/yuanchenqi/articles/5980312.html
浙公网安备 33010602011771号