一. 注册事件处理程序
可以使用:
1 通过HTML标签属性注册事件处理程序
2 通过DOM元素属性注册事件处理程序
注意:通过上面这种方式添加事件,同一个类型的事件如果添加多次的话,只执行最后添加的事件。
3 使用addEventListener()方法注册事件处理程序
-
addEventListener事件绑定、监听、捕获 ---》标准浏览器中有作用,非标准IE不兼容
-
语法:元素.addEventListener(事件名,函数,true/false) true代表事件捕获,false代表事件冒泡。
-
由于现在的浏览器都是执行事件冒泡,所以第三个参数通常写成false。
注意:同一种类型的事件可以添加多次,执行顺序是先添加会先执行,后面依次执行。
如下是代码详情:
<!-- 不推荐 -->
<div onclick="alert('点我干啥')">我是boss</div>
<!--第二种 -->
<div id="box">给元素绑定事件</div>
<!-- 第三种 -->
<!-- 使用addEventListener()方法注册事件处理程序-->
<div id="box1">通过addEventListener方法注册事件</div>
<script>
var box = document.getElementById('box');
box.onclick = function () {
console.log('绑定点击事件')
}
var box1 = document.getElementById('box1');
// box1.addEventListener('事件类型','事件的处理函数')
box1.addEventListener('click',function(){
console.log('绑定点击事件')
})
var box2 = document.getElementById('box2');
// window.addEventListener('resize',function(){
// })
</script>
二. 事件处理程序
事件就是用户或浏览器自身执行的某种动作。比如click、load和mouseover,都是事件的名字。而相应事件的函数就叫做事件处理程序(或事件侦听器)。
2.1 添加事件处理程序的两种方法
-
第一种:“on”加事件类型,如onclick、onload等;
var btn = document.getElementsByTagName("button")[0]; btn.onclick = function(){ alert("点击事件被触发了1"); }
注意:通过上面这种方式添加事件,同一个类型的事件如果添加多次的话,只执行最后添加的事件。
-
第二种是通过addEventListener()方法:
btn.addEventListener("dblclick", function(){ alert("双击1"); }); btn.addEventListener("dblclick", function(){ alert("双击2"); });
同一种类型的事件可以添加多次,执行顺序是先添加会先执行,后面依次执行。
2.2移除事件绑定
<!-- 不推荐 -->
<div onclick="alert('点我干啥')">我是boss</div>
<!--第二种 -->
<div id="box">给元素绑定事件</div>
<!-- 第三种 -->
<!-- 使用addEventListener()方法注册事件处理程序-->
<div id="box1">通过addEventListener方法注册事件</div>
<div id="box2">移除事件</div>
<script>
var box = document.getElementById('box');
box.onclick = function () {
console.log('绑定点击事件')
}
var box1 = document.getElementById('box1');
// box1.addEventListener('事件类型','事件的处理函数')
function fn(e){
console.log('绑定点击事件',e)
}
box1.addEventListener('click',fn)
var box2 = document.getElementById('box2');
// window.addEventListener('resize',function(){
// })
box2.onclick = function(){
box1.removeEventListener('click',fn)
box.onclick = null
}
</script>
三. 事件的传递过程(事件冒泡)
JS和HTMl元素的交互几乎都是通过“事件”来完成的,事件从触发到完成响应一般分为3个阶段:捕获阶段,目标阶段,和冒泡阶段。
-
捕获阶段
:事件从根节点流向目标节点,途中流经各个DOM节点,在各个节点上触发捕获事件,直到达到目标节点。 -
目标(target)阶段
:在此阶段中,事件传导到目标节点。浏览器在查找到已经指定给目标事件的监听器后,就会运行该监听器。 -
事件冒泡
: 当为多个嵌套的元素设置了相同的事件处理程序,它们将触发事件冒泡机制。在事件冒泡中,最内部的元素将首先触发其事件,然后是栈内的下一个元素触发该事件,以此类推,直到到达最外面的元素。如果把事件处理程序指定给所有的元素,那么这些事件将依次触发。
从图中我们可以知道
-
1、一个完整的JS事件流是从window开始,最后回到window的一个过程
-
2、事件流被分为三个阶段(1-5)捕获过程、(5-6)目标过程、(6-10)冒泡过程
//事件捕获的演示
<style>
.father {
width: 600px;
height: 600px;
border: 3px solid red;
}
.son {
width: 200px;
height: 200px;
background-color: #ff534c;
}
</style>
</head>
<body>
<div class="father">
这是father
<div class="son">这是儿子</div>
</div>
<script>
// 获取到元素
var father= document.getElementsByClassName('father')[0];
var son = document.getElementsByClassName('son')[0];
// 事件绑定
// addEventListener('事件类型','处理函数','boolen是否捕获')
// true 捕获阶段 默认是false 冒泡阶段
document.addEventListener('click',function(e){
console.log('document',e);
},true)
father.addEventListener('click',function(e){
console.log('father',e);
},true)
son.addEventListener('click',function(e){
console.log('son',e);
},true)
</script>
//事件的传递过程
<style>
.father {
width: 600px;
height: 600px;
border: 3px solid red;
}
.son {
width: 200px;
height: 200px;
background-color: #ff534c;
}
</style>
</head>
<body>
<div class="father">
这是father
<div class="son">这是儿子</div>
</div>
<script>
// 获取到元素
var father= document.getElementsByClassName('father')[0];
var son = document.getElementsByClassName('son')[0];
// 事件的绑定
// 从内向外触发事件
// 并不是所有的事件都能冒泡
//
document.onclick = function(){
console.log('document')
}
father.onclick = function(){
console.log('father')
}
son.onclick = function(){
console.log('son')
}
// 事件从触发到完成响应一般分为3个阶段:捕获阶段,目标阶段,和冒泡阶段
</script>
//阻止冒泡
<style>
.father {
width: 600px;
height: 600px;
border: 3px solid red;
}
.son {
width: 200px;
height: 200px;
background-color: #ff534c;
}
</style>
</head>
<body>
<div class="father">
这是father
<div class="son">这是儿子</div>
</div>
<script>
// 获取到元素
var father= document.getElementsByClassName('father')[0];
var son = document.getElementsByClassName('son')[0];
// 事件的绑定
// 从内向外触发事件
// 并不是所有的事件都能冒泡
father.onclick = function(){
console.log('father')
}
son.onclick = function(e){
console.log('e',e)
console.log('son')
// 阻止时间传播 e.stopPropagation()
e.stopPropagation()
}
// 事件从触发到完成响应一般分为3个阶段:捕获阶段,目标阶段,和冒泡阶段
</script>
四. 事件委托
事件委托: 原本绑定在子元素身上的事件,现在绑定到父元素上,利用事件冒泡的传递的过程,来触发当前的事件,这样的做法叫做事件委托,也叫事件代理。
<ul id="ulList">
<li>这是第一个li</li>
<li>这是第二个li</li>
<li>这是第三个li</li>
</ul>
<script>
// var lis = document.getElementsByTagName('li');
// for(var i=0;i<lis.length;i++){
// lis[i].onclick = function(){
// console.log('每一个li',this)
// }
// }
// 事件委托:原本绑定在子元素上面的事件,现在绑定到父元素上面了
// 事件委托又叫事件代理--提升代码的执行效率
var ulList = document.getElementById('ulList');
ulList.onclick = function(e){
console.log('e',e.target)
}
</script>
五. 阻止事件传播
使用事件对象的 stopPropagation() 方法停止事件传播。
六. 阻止默认事件
方法一:使用事件对象的 preventDefault() 方法阻止默认行为。
方法二:在事件的处理函数中返回 false。
七.javascript中常用坐标属性
7.1 MouseEvent属性
由鼠标事件(MouseEvent)可以发现: 其中包含了许多的坐标,且每个坐标的含义都不一样。下面我们来挨个介绍常用的坐标,以及它们的含义。
-
1.clientX、clientY 点击位置距离当前body可视区域的x,y坐标
-
2.pageX、pageY(不会随着滚动条的滚动而改变) 对于整个页面来说,包括了被卷去的body部分的长度,相对文档区域左上角距离
-
3.screenX、screenY 点击位置距离当前电脑屏幕的x,y坐标
-
4.offsetX、offsetY 鼠标相对于事件源元素的x,y坐标(光标相对于自身盒子内侧的坐标,不包括边框)
<style>
*{
margin: 0;
padding: 0;
}
.box{
width: 200px;
height: 4000px;
border: 20px solid red;
padding: 20px;
margin: 50px;
}
</style>
</head>
<body>
<div class="box">
</div>
<script>
var box = document.getElementsByClassName('box')[0];
box.onclick = function(e){
// clientX: 鼠标相对于浏览器可视区的x坐标 浏览器的左上角为坐标原点
// clientY: 鼠标相对于浏览器可视区的y坐标浏览器的左上角为坐标原点
// console.log('ex',e.clientX);
// console.log('ey',e.clientY);
// pageX、pageY
// 对于整个页面来说,包括了被卷去的body部分的长度,相对文档区域左上角距离
// console.log('ex',e.pageX);
// console.log('eY',e.pageY);
// screenX、screenY
// 点击位置距离当前电脑屏幕的x,y坐标
// console.log('screenX',e.screenX);
// console.log('screenY',e.screenY);
// offsetX、offsetY
// 鼠标相对于事件源元素的x,y坐标(光标相对于自身盒子内侧的坐标,不包括边框)
console.log('offsetX',e.offsetX)
console.log('offsetY',e.offsetY)
}
</script>
//小盒子随鼠标移动的一个小案例
<style>
.box{
width: 200px;
height: 200px;
background-color: red;
position: fixed;
}
</style>
</head>
<body>
<div class="box">
</div>
<script>
// 获取元素
var box = document.getElementsByClassName('box')[0];
// 鼠标移动事件
document.onmousemove = function(e){
console.log('e',e)
box.style.left = e.clientX +'px'
box.style.top = e.clientY +'px'
}
</script>
7.2 元素(HTMLElement)的offset属性(重点)
offset这个属性,可以说是非常有用的,顾名思义,offset翻译过来就是偏移量,从名字就可以看出它的具体意义了。也即是元素相当于父元素的偏移量。
-
1.offsetTop: 元素相对父元素上边的偏移。(只读)
-
2.offsetLeft: 元素相对父元素左边的偏移。(只读)
-
3.offsetWidth: 自身包括padding 、 边框、内容区的宽度。
-
4.offsetHeight: 自身包括padding、边框、内容区的高度。
-
5.offsetParent: 作为偏移参照点的父级元素。
offsetLeft 和left 的区别
如果父div的position定义为relative,子div的position定义为absolute,那么子div的style.left的值是相对于父div的值,这同offsetLeft是相同的。
区别在于:
-
style.left 返回的是字符串,如28px,offsetLeft返回的是数值28,如果需要对取得的值进行计算, 还用offsetLeft比较方便。
-
style.left是读写的,offsetLeft是只读的,所以要改变div的位置,只能修改style.left。
<style>
.father{
width: 900px;
height: 600px;
border: 3px solid red;
margin: 50px 0;
position: relative;
}
.son{
width: 100px;
height: 100px;
border: 20px solid blue;
position: absolute;
left: 20px;
top: 40px;
}
</style>
</head>
<body>
<div class="father">
father
<div class="son"></div>
</div>
<script>
var son = document.getElementsByClassName('son')[0];
// 子绝父相 获取到的是距离父元素左上角的位置
// console.log(son.offsetLeft);//可读就意味着只能获取不能设置值
// console.log(son.offsetTop);
// - 3.offsetWidth: 自身包括padding 、 边框、内容区的宽度。
// - 4.offsetHeight: 自身包括padding、边框、内容区的高度。
console.log(son.offsetWidth);
console.log(son.offsetHeight);
// 作为偏移参照点的父级元素。
console.log(son.offsetParent);
</script>
7.3 元素的client属性
-
clientHeight(clientWidth):内容可视区域的高度/宽度,也就是说页面浏览器中可以看到内容的这个区域的高度(不含边框,也不包含滚动条等边线)
-
clientLeft,clientTop: 这两个返回的是元素周围边框的厚度,可以理解为边框的长度,如果不指定一个边框或者不定位改元素,他的值就是0.
<style>
.box{
width: 200px;
height: 200px;
padding: 10px;
/* background-color: red; */
border-left: 20px solid #000;
border-top: 20px solid #ff534c;
}
</style>
</head>
<body>
<div class="box">
</div>
<script>
var box = document.getElementsByClassName('box')[0];
console.log('box.offsetWidth',box.offsetWidth);
console.log('box.offsetHeight',box.offsetHeight);
// 不含边框,也不包含滚动条等边线
console.log('box.clientWidth',box.clientWidth);
console.log('box.clientHeight',box.clientHeight);
console.log('box.clentLeft',box.clientLeft);
console.log('box.clientTop',box.clientTop);
</script>
7.4 元素的scroll 属性
scroll 翻译过来就是滚动的,我们使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。
<style>
.box{
width: 200px;
height: 300px;
border: 3px solid red;
overflow: auto;
}
</style>
</head>
<body>
<div class="box">
足够多的内容
</div>
<script>
var box = document.querySelector('.box');
box.onclick = function(){
//scrollTop 被卷进去的距离 垂直方法
// console.log(box.scrollTop);
// 获取内容的宽度 不包含滚动条
console.log(box.scrollWidth)
// 内容的高度 不包含滚动条
console.log(box.scrollHeight)
}
</script>
7.5 window属性
-
window.pageXOffset 获取当前页面相对于窗口显示区左上角的 X 位置。(页面滚动的距离)
-
window.pageYOffset 获取当前页面相对于窗口显示区左上角的 Y 位置。(只读)
-
window.screenLeft 可以获得浏览器距屏幕左上角的左边距
-
window.screenTop 可以获得浏览器距屏幕左上角的上边距
-
window.screen.width记录了客户端显示屏的宽
-
window.screen.height记录了客户端显示屏的高
-
window.innerWidth:返回以像素为单位的窗口的内部宽度。如果垂直滚动条存在,则这个属性将包括它的宽度。(只读)
-
window.innerHeight:返回以像素为单位的窗口的内部高度。如果有水平滚动条,也包括滚动条高度。(只读)
<style>
.box {
width: 300px;
height: 3000px;
border: 2px solid red;
}
</style>
</head>
<body>
<div class="box">
</div>
<script>
// - window.pageXOffset 获取当前页面相对于窗口显示区左上角的 X 位置。(页面滚动的距离)
// - window.pageYOffset 获取当前页面相对于窗口显示区左上角的 Y 位置。(只读)
// - window.screenLeft 可以获得浏览器距屏幕左上角的左边距
// - window.screenTop 可以获得浏览器距屏幕左上角的上边距
// - window.screen.width记录了客户端显示屏的宽
// - window.screen.height记录了客户端显示屏的高
var box = document.getElementsByClassName('box')[0];
box.onclick = function () {
console.log(window.pageXOffset);
console.log(window.pageYOffset);//重点
console.log(window.screenLeft);
console.log(window.screenTop);
console.log('屏幕W', window.screen.width);
console.log('屏幕H', window.screen.height);
// - window.innerWidth:返回以像素为单位的窗口的内部宽度。如果垂直滚动条存在,则这个属性将包括它的宽度。(只读)
// - window.innerHeight:返回以像素为单位的窗口的内部高度。如果有水平滚动条,也包括滚动条高度。(只读)
console.log('窗口W', window.innerWidth);
console.log('窗口H', window.innerHeight);
}
</script>