
JavaScript核心
一、文档对象模型(DOM)
1.1基本概念
DOM是JavaScript操作网页的接口,全称为“文档对象模型”(Document Object Model)。 它的作用是将网页转为一个JavaScript对象,从而可以用脚本进行各种操作(增删改查)。
浏览器会根据DOM模型,将结构化文档(比如HTML和XML)解析成一系列的节点, 再由这些节点组成一个树状结构(DOM Tree)。 所有的节点和最终的树状结构,都有规范的对外接口。
JavaScript是一门编程语言,而DOM是浏览器对HTML文档结构化后的一个模型;
严格地说,DOM不属于JavaScript,但是我们最常用的就是使用JavaScript操作DOM;

1.2节点的概念
DOM的最小组成单位叫做节点(node)。文档的树形结构(DOM树),就是由各种不同类型的节点组成。
每个节点都可以看作是文档树的一片叶子。
最顶层的节点就是document节点,它代表了整个文档;是文档的根节点。
每张网页都有自己的document节点,window.document属性就指向这个节点的。
只要浏览器开始载入HTML文档,这个节点对象就存在了,可以直接调用。
每一个HTML标签元素,在DOM树上都会转化成一个Element节点对象;
文档里面最高一层一般是HTML标签,其他HTML标签节点都是它的下级。
除了根节点以外,其他节点对于周围的节点都存在三种关系:
父节点关系(parentNode):直接的那个上级节点
子节点关系(childNodes):直接的下级节点
同级节点关系(sibling):拥有同一个父节点的节点常用dom操作:
查找页面的标签元素
标签增加、修改、删除等操作
标签的属性相关操作
给标签元素绑定事件(设置当什么什么时候,做什么什么事情)
1.3查找节点
上一节我们知道,整个文档的节点就是document节点,那么想要具体找到某个节点, 我们可以使用document提供的一系列方法:
<div>
<p id="p1">1111111111</p>
<i>2222222222</i>
<p class='p'>1111111111</p>
<i>2222222222</i>
<p class="p">1111111111</p>
<i>2222222222</i>
<div id="p">
<p name="p">3333333333</p>
</div>
</div>
getElementsByTagName() 返回所有指定HTML标签的元素,返回值是一个类似数组的HTMLCollection对象;匹配失败,返回[] 参数是想要获取节点的具体节点名称,就是 标签名;
var p = document.getElementsByTagName('p');
//标签节点.style.样式名 = '样式值' 可以给标签节点设置css样式
p[3].style.background = 'red';getElementsByClassName() 返回所有class名字符合指定条件的元素,返回值是一个类似数组的HTMLCollection对象;匹配失败,返回[] 参数为 标签的class属性的值
var p = document.getElementsByClassName('p');
p[1].style.background = 'yellow';getElementsByName() 选择拥有name属性的HTML元素,返回值是一个类似数组的HTMLCollection对象;匹配失败,返回[] 参数为 标签的name属性的值; 注意,使用时,最好选择原生具有name属性的元素;
var p = document.getElementsByName('p');
p[0].style.background = 'yellow';getElementById() 返回匹配指定id属性的元素节点;没有发现匹配的节点,则返回null 参数为 标签的id属性的值,参数大小写敏感;
var p = document.getElementById('p');
p.style.background = 'yellow';querySelector()、querySelectorAll() document.querySelector方法接受一个CSS选择器作为参数,返回匹配该选择器的元素节点; 如果有多个节点满足匹配条件,则返回第一个匹配的节点。如果没有发现匹配的节点,则返回null;
document.querySelectorAll方法与querySelector用法类似, 区别是返回一个类似数组的HTMLCollection对象,包含所有匹配给定选择器的节点。
var p = document.querySelector('.p');
p.style.background = 'yellow';var p = document.querySelectorAll('.p');
p[1].style.background = 'yellow';多个参数值,使用,(英文逗号)隔开,而querySelector()返回第一个选中的节点;
var p = document.querySelectorAll('i,.p');
for(var i=0;i<p.length;i++){
p[i].style.background = 'yellow';
}这两个方法都支持复杂的CSS选择器。
//选中 id 属性值为p1的元素
// var p = document.querySelectorAll('[id="p1"]');
//选中div元素的class属相值为p的元素
// var p = document.querySelectorAll('div.p');
//选中所有的p标签,但是class值为p的除外
var p = document.querySelectorAll('p:not(.p)');
for(var i=0;i<p.length;i++){
p[i].style.background = 'yellow';
}但是,它们不支持CSS伪元素的选择器(比如:first-line和:first-letter) 和伪类的选择器(比如:link和:visited),即无法选中伪元素和伪类。
二、事件
2.1什么是事件
一种 触发—响应 的机制;
用户的行为 + 浏览器感知(捕获)到用户的行为 + 事件处理程序
事件三要素:
- 事件源:(被)触发事件的元素
- 事件类型:事件的触发方式(例如鼠标点击或键盘点击)
- 事件处理程序:事件触发后要执行的代码(函数形式)
2.2事件绑定
- 行内方式绑定(元素属性)
<body>
<input type="button" value="按钮" id="btn" οnclick="alert(2)">
</body>
<body>
<input type="button" value="按钮" id="btn" οnclick="f()">
</body>
<script>
function f(){
console.log(3);
}
</script>onclick 其实就是html元素的一个属性,而属性的值需要是 一段可执行的JS代码
- 动态绑定 (节点对象属性)
<body>
<input type="button" value="按钮" id="btn">
</body>
<script>
var btn = document.getElementById('btn');
btn.onclick = function(){
alert(4);
}
</script>获取节点对象,然后 修改 节点对象 的 属性 onclick 的值,值是一个 匿名函数 即可;
以上两种事件绑定方式,需要在事件名称前加 on ;
- 事件监听(节点对象方法)
<body>
<input type="button" value="按钮" id="btn">
</body>
<script>
var btn = document.getElementById('btn');
btn.addEventListener('click',function(){
alert(5);
});
</script>每一个节点对象都提供了 addEventListener 方法,这个方法可以给选中的节点添加指定类型的事件及事件处理程序;
- 移除事件监听
<body>
<input type="button" value="按钮" id="btn">
</body>
<script>
function f(){
alert(5);
}
var btn = document.getElementById('btn');
btn.addEventListener('click',f);
btn.removeEventListener('click',f);
</script>注意: removeEventListener方法移除的监听函数, 必须与对应的addEventListener方法的参数完全一致, 而且必须在同一个元素节点,否则无效。
2.3三种事件绑定比较
this关键字 在JavaScript中,每一个函数的内部都存在一个this关键字,其随着运行环境的不同,其指向也是不同的。
<body>
<p id="t">ttttt</p>
</body>
<script>
var d = document.getElementById('t');
d.onclick = function(){
//this指代本对象 就是 d
console.log(this);
}
</script>
将上述代码的动态绑定,改为行内绑定:
<body>
<p id="t" onclick="f()">ttttt</p>
</body>
<script>
function f(){
console.log(this); //window对象
}
</script>
由此可知: 行内绑定,其事件处理程序内部的this指向了全局的window对象。 动态绑定,其事件处理程序内部的this指向了当前正在操作的dom对象。
需求:同一个元素的同一个事件,绑定多个处理函数:
<body>
<!--行内绑定,谁在前谁执行-->
<p id="t" onclick="t()" onclick="f()">ttttt</p>
</body>
<script>
function f(){
alert(1);
}
function t(){
alert(2);
}
</script>
<body>
<p id="t" >ttttt</p>
</body>
<script>
//动态绑定,后边的执行函数会将前面的覆盖掉
var d = document.getElementById('t');
d.onclick = function(){
alert(1);
}
d.onclick = function (){
alert(2);
}
</script>
<body>
<p id="t" >ttttt</p>
</body>
<script>
var d = document.getElementById('t');
function f1() {
console.log(this);
}
d.addEventListener('click', f1, false);
d.addEventListener('click', function(){console.log('f2');}, false);
</script>
总结: 第一种 "HTML标签的on-属性",违反了HTML与JavaScript代码相分离的原则;处理函数中 this 指向的window对象; 第二种 "Element节点的事件属性" 的缺点是,同一元素同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次。但是处理函数中的 this 指向的选中的对象; 第三种:addEventListener方法可以针对同一个元素的同一个事件,添加多个监听处理函数。处理函数中的 this 指向的也是选中的元素;
2.4事件类型
事件类型一览表:
2.4.1页面事件(资源事件)
事件名称 |
何时触发 |
load |
一个资源及其相关资源已完成加载。 |
<body onload="f1()" >
</body>
<script>
function f1(){
alert('f1');
}
</script>
2.4.2焦点事件
事件名称 |
何时触发 |
focus |
元素获得焦点 |
blur |
元素失去焦点 |
<body>
<input type="text" id="t" value="请输入用户名" onfocus="f1()" onblur="f2()">
</body>
<script>
function f1(){
document.getElementById('t').value = '';
}
function f2(){
var v = document.getElementById('t').value;
alert(v);
}
</script>
2.4.3鼠标事件
事件名称 |
何时触发 |
mouseenter |
指针移到有事件监听的元素内 |
mouseover |
指针移到有事件监听的元素或者它的子元素内 |
mousemove |
指针在元素内移动时持续触发 |
mousedown |
在元素上按下任意鼠标按钮 |
mouseup |
在元素上释放任意鼠标按键 |
click |
在元素上按下并释放任意鼠标按键 |
dblclick |
在元素上双击鼠标按钮 |
contextmenu |
右键点击 (右键菜单显示前). |
mouseleave |
指针移出元素范围外(不冒泡) |
mouseout |
指针移出元素,或者移到它的子元素上 |
select |
文本被选中(input标签、textarea标签) |
copy |
元素内容被拷贝时 |
<body>
<div id="d" style="width:200px;height:200px;border:1px solid red">
来啊
</div>
</body>
<script>
var d = document.getElementById('d');
//当鼠标悬浮时触发
d.onmouseover = function(){
console.log('来了?');
}
//当鼠标离开时触发
d.onmouseout = function(){
console.log('不要啊');
}
//当鼠标按下时触发
d.onmousedown = function(){
console.log('用力啊');
}
//当鼠标弹起时触发
d.onmouseup = function(){
console.log('再来');
}
//当鼠标移动时触发
d.onmousemove = function(){
console.log('别乱动');
}
//当点击右键时
d.oncontextmenu = function(){
console.log('你想干什么?');
return false;
}
// 当复制内容时
d.oncopy = function(){
console.log('你敢复制我?');
return false;
}
</script>
2.4.4键盘事件
事件名称 |
何时触发 |
keydown |
按下任意按键 |
keypress |
除 Shift, Fn, CapsLock 外任意键被按住. (连续触发) |
keyup |
释放任意按键 |
<body>
<input type="text" value="" id="t">
</body>
<script>
var d = document.getElementById('t');
//当键盘按下时触发
d.onkeydown = function(){
console.log('推到?');
}
//当键盘按下时触发
d.onkeypress = function(){
console.log('撩起2?');
}
//当键盘弹起时触发
d.onkeyup = function(){
console.log('撩起?');
}
</script>
2.4.5form表单事件
Event Name |
Fired When |
reset |
点击重置按钮时 (<input type=’reset’ value=’重置’ />) |
submit |
点击提交按钮 |
<body>
<form id="f" action="1.2.5.php">
姓名:<input type="text" name="" value=""> <br>
<input type="submit" name="" value="提交">
<input type="reset" name="" value="重置">
</form>
</body>
<script>
var d = document.getElementById('f');
//当表单提交时触发
d.onsubmit = function(){
alert('t');
}
//当表单重置时触发
d.onreset = function(){
alert('re');
}
</script>
2.4.6内容变化事件
change: 当内容改变且失去焦点时触发 (存储事件) input : 当内容改变时触发 (值变化事件)
<body>
<input type="text" id="t" value="">
</body>
<script>
var d = document.getElementById('t');
//当内容改变且失去焦点时触发
d.onchange = function(){
console.log('t');
}
//当内容改变时触发
d.oninput = function(){
console.log('in');
}
</script>
2.5事件的传播
三个包裹着的DIV,都绑定了点击事件,问: 当点击 div1 时,会发生什么现象?
<head>
<title></title>
<meta charset="UTF-8">
<style>
div{padding: 40px}
#div3{width: 300px;height: 300px;background-color: red}
#div2{width: 200px;height: 200px;background-color: yellow}
#div1{width: 100px;height: 100px;background-color: blue}
</style>
</head>
<body>
<div id="div3">3
<div id="div2">2
<div id="div1">1</div>
</div>
</div>
</body>
<script>
var d1 = document.getElementById('div1');
var d2 = document.getElementById('div2');
var d3 = document.getElementById('div3');
d1.onclick = function(){
alert('1');
}
d2.onclick = function(){
alert('2');
}
d3.onclick = function(){
alert('3');
}
</script>

当点击div1时,触发 事件1,但是,紧跟着,事件2和事件3也被触发了;
这种现象,我们称为 事件冒泡
在JS中当一个事件发生以后,它会在不同的DOM节点之间传播。 这种传播分成三个阶段: 第一阶段:从window对象传导到目标节点,称为 捕获阶段。 第二阶段:在目标节点上触发,称为 目标阶段。 第三阶段:从目标节点传导回window对象,称为 冒泡阶段。

事件传播的最上层对象是window; 事件的传播顺序,在捕获阶段依次为window、document、html、body、div; 在冒泡阶段依次为div、body、html、document、window。
注意: 三种事件绑定方式全部 默认 监听冒泡阶段事件;
2.6改变事件触发的阶段
想让事件监听在捕获阶段,只能通过 addEventListener 方法的进行设置:
<script>
var d1 = document.getElementById('div1');
var d2 = document.getElementById('div2');
var d3 = document.getElementById('div3');
d1.addEventListener('click',function(){
alert('m1');
});//目标阶段触发
d2.addEventListener('click',function(){
alert('b2');
},true);//捕获阶段触发
d3.addEventListener('click',function(){
alert('b3');
},true);//捕获阶段触发
d1.addEventListener('click',function(){
alert('mm1');
});//目标阶段触发
d2.addEventListener('click',function(){
alert('p2');
});//冒泡阶段触发
d3.addEventListener('click',function(){
alert('p3');
},false);//冒泡阶段触发
</script>
2.7案例
为选中的的元素绑定事件
<body>
<input type="button" value="按钮" id="btn" />
<script>
//根据id获取元素
document.getElementById("btn").onclick=function () {
alert("哈哈,我又变帅了");
};
</script>
</body>
一次性事件案例(下载按钮点一次则失效)
<body>
<input type="button" id="btn" value="下载">
</body>
<script>
var btn = document.getElementById('btn');
function f(){
alert(123);
btn.removeEventListener('click',f);
}
btn.addEventListener('click',f);
</script>
点击每个图片弹出对话框
<body>
<img src="images/1-small.jpg" alt="" />
<img src="images/2-small.jpg" alt="" />
<img src="images/3-small.jpg" alt="" />
<script>
//点击每个图片都可以弹出对话框
//根据标签名字获取元素,分别注册点击事件,分别添加事件处理函数
var imgObjs=document.getElementsByTagName("img");
//遍历
for(var i=0;i<imgObjs.length;i++){
//为每个图片元素注册点击事件,添加事件处理函数
imgObjs[i].onclick=function () {
alert("啊,我被点击了");
};
}
</script>
</body>