这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
注册事件的其他方法
打点调用onclick
之前介绍过, 这里不再赘述.
var btn = document.getElementById("btn");
btn.onclick = function(){
alert(1);
};
element.addEventListener() 方法
• element.addEventListener() 方法。
• 参数:
第一个参数:事件类型的字符串(直接书写”click”,不需要加 on)
第二个参数:事件函数
注意:
-
同一个元素可以多次绑定事件监听,同一个事件类型可以注册多个事件函数, 事件会根据书写的顺序进行一个事件排队
-
兼容性问题:不支持 IE9 以下的浏览器
var btn = document.getElementById("btn");
// DOM 2 级事件绑定方式
btn.addEventListener("click",function () {
alert(1);
});
// 多次绑定相同的事件类型,事件会根据书写的顺序进行一个事件排队
btn.addEventListener("click",clickEvent);
function clickEvent() {
alert(2);
}
element.attachEvent() 方法
• element.attachEvent() 方法。
• 参数:
第一个参数:事件类型的字符串(需要加 on)
第二个参数:事件函数
注意:
同一个元素可以多次绑定事件监听,同一个事件类型可以注册多个事件函数
兼容性问题:只支持 IE10 及以下的浏览器. 但在IE中也有兼容性问题, IE8 及以下的浏览器处理事件队列时,会出现顺序错乱
var btn = document.getElementById("btn");
// DOM 2 级事件绑定方式
// 兼容:IE 10 及以下浏览器
btn.attachEvent("onclick",function () {
alert(3);
});
btn.attachEvent("onclick",clickEvent);
function clickEvent() {
alert(4);
}
注册事件的兼容写法
自定义一个注册事件函数
• 参数:事件源,事件类型(不加 on),事件函数
IE9 及以上的浏览器,使用 addEventListener() 方法
IE9 以下的浏览器,使用 attachEvent() 方法
判断浏览器时,不需要判断它的版本,可以检测浏览器能力
浏览器能力检测:将某个方法的调用作为 if 语句的判断条件,如果浏览器认识该方法返回
true,否则返回 false。
<body>
<input type="button" value="点击" id="btn">
<script>
var btn = document.getElementById("btn");
// 调用函数
addEvent(btn,"click",function () {
alert(1);
});
// DOM 2 级事件绑定方式
// 自己制作一个兼容所有浏览器的绑定事件的函数
// 参数:事件源,事件类型,事件函数
function addEvent(ele,type,fn) {
// IE 9 及以上的浏览器和其他浏览器,使用 addEventListener 方法
// 浏览器能力检测
if (ele.addEventListener) {
ele.addEventListener(type,fn);
// IE 9 以下的浏览器,使用 attachEvent 方法
} else if (ele.attachEvent) {
ele.attachEvent("on" + type,fn);
}
}
</script>
</body>
移除绑定事件
onclick的移除
btn.onclick = null;
element.removeEventListener() 方法
• element.removeEventListener() 方法。
参数:
第一个参数:事件类型的字符串(直接书写”click”,不需要加 on)
第二个参数:事件函数引用名
注意:
没有办法移除一个匿名函数,所以在注册事件时需要单独声明一个有函数名的事件函数。
兼容性问题:不支持 IE9 以下的浏览器
btn.removeEventListener("click",fun);
element.detachEvent() 方法
• element.detachEvent() 方法。
• 参数:
第一个参数:事件类型的字符串(需要加 on)
第二个参数:事件函数
注意:
没有办法移除一个匿名函数,所以在注册事件时需要单独声明一个有函数名的事件函数。
兼容性问题:只支持 IE10 及以下的浏览器
btn.detachEvent("onclick",fun);
移除事件的兼容写法
自定义一个移除事件函数
• 参数:事件源,事件类型(不加 on),事件函数
IE9 及以上的浏览器,使用 removeEventListener 方法
IE9 以下的浏览器,使用 detachEvent 方法
建议:将自己封装的一些常用函数和方法,放到一个单独的 .js 文件中。
<body>
<input type="button" value="点击" id="btn">
<script>
var btn = document.getElementById("btn");
// 调用函数
addEvent(btn,"click",fun);
// 移除事件
removeEvent(btn,"click",fun);
function fun() {
alert(1);
}
// DOM 2 级事件绑定方式
// 自己制作一个兼容所有浏览器的绑定事件的函数
// 参数:事件源,事件类型,事件函数
function addEvent(ele,type,fn) {
// IE 9 及以上的浏览器和其他浏览器,使用 addEventListener 方法
// IE 9 以下的浏览器,使用 attachEvent 方法
// 浏览器能力检测
if (ele.addEventListener) {
ele.addEventListener(type,fn);
} else if (ele.attachEvent) {
ele.attachEvent("on" + type,fn);
}
}
// 兼容所有浏览器的 解除绑定事件的函数
// 参数:事件源,事件类型,事件函数
function removeEvent(ele,type,fn) {
// 浏览器能力检测
if (ele.removeEventListener) {
ele.removeEventListener(type,fn);
} else if (ele.detachEvent) {
ele.detachEvent("on" + type,fn);
}
}
</script>
</body>
DOM 事件流
捕获: 从祖先级流向子级
冒泡: 从子级流向祖先级
先捕获后冒泡
事件流的三个阶段
• 第一个阶段:事件捕获
• 第二个阶段:事件执行过程
• 第三个阶段:事件冒泡
addEventListener()
addEventListener 有第三个参数,用来决定事件流的方向. 参数值是布尔类型的值.
addEventListener() 第三个参数为 false 时,事件冒泡
addEventListener() 第三个参数为 true 时,事件捕获
参数默认值是 false
onclick
onclick 类型:只能进行事件冒泡过程,没有捕获阶段
attachEvent()
attachEvent() 方法:只能进行事件冒泡过程,没有捕获阶段
事件委托
利用事件冒泡,将子级的事件委托给父级加载
同时,需要利用事件函数的一个 e 参数,内部存储的是事件对象. 只要触发事件,函数内部都可以得到一个事件对象,对象中存储了关于事件的一系列数据. e.target 属性记录的就是真正触发事件的事件源.
<body>
<ul id="list">
<li>刘亦菲</li>
<li>杨幂</li>
<li>唐嫣</li>
<li>赵丽颖</li>
<li>刘诗诗</li>
</ul>
<script>
// 让每个 li 被点击后,自己添加特殊的背景色,而其他兄弟不添加
// 以前的思路:获取所有的 li 标签元素,批量添加事件
// 事件委托:可以将一些子级的公共类型的事件委托给他们的父级添加,在父级内部想办法找到真正触发事件的最底层的事件源
// 获取元素
var list = document.getElementById("list");
var lis = list.children;
// 给 ul 添加点击事件
list.onclick = function (e) {
// 在内部要想办法找到真正触发事件的 li
// 借用事件函数内部的一个参数 e,e 是事件对象
// 只要触发事件,函数内部都可以得到一个事件对象,对象中存储了关于事件的一系列数据
// e.target 属性记录的就是真正触发事件的事件源
// 排除其他
for (var i = 0 ; i < lis.length ; i++) {
lis[i].style.backgroundColor = "";
}
e.target.style.backgroundColor = "pink";
};
</script>
</body>
事件对象
只要触发事件,就会有一个对象,内部存储了与事件相关的数据。
e 在低版本浏览器中有兼容问题,低版本浏览器使用的是 window.event
事件对象常用的属性:
e.eventPhase 查看事件触发时所处的阶段, 阶段是用数字表示的
( 1: 捕获阶段 2: 目标阶段 3:冒泡阶段 )
e.target 用于获取触发事件的元素
e.srcElement 用于获取触发事件的元素,低版本浏览器使用
e.currentTarget 用于获取绑定事件的事件源元素, 也就是this的指代
e.type 获取事件类型 (没有on)
client系列: 客户端尺寸,点击的点参考浏览器窗口左上角的距离
e.clientX/e.clientY 所有浏览器都支持,返回鼠标点击位置距离浏览器窗口左上角的距离 (可以用于设置图片随鼠标移动等)
page 系列:html 页面尺寸,点击的点参考html文档左上角的距离
e.pageX/e.pageY IE8 以前不支持,鼠标点击位置距离整个HTML页面左上顶点的距离
例1 e.target e.currentTarget this 之间的关系:
<body>
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
<script>
// 获取元素
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
var box3 = document.getElementById("box3");
// 添加事件
box1.onclick = function (e) {
// e指的就是存储事件对象的参数,只要事件被触发,e就会自动接收数据
// 兼容问题
e = e || window.event;
// 获取真正触发事件的元素
var target = e.target || e.srcElement;
console.log(target);
// 获取绑定事件的事件源元素
console.log(e.currentTarget);
// this 指向
console.log(this);
};
</script>
</body>
当点击box3这个元素时, 控制台输出如下:
可以看出:
e.target 指的是鼠标直接点击的元素
e.currentTarget 指的是绑定事件的事件源元素
this 与e.currentTarget一样, 也是指绑定事件的事件源元素
例2 e.type
// 很多时候可能给同一个元素对象添加不同的事件类型,对应执行的事件函数内部的代码不同
//按照以前的方法需要分别写两个函数
box1.onmouseover = function () {
box1.style.backgroundColor = "skyblue";
};
box1.onmouseout = function () {
box1.style.backgroundColor = "yellowgreen";
};
如果使用e.type, 就可以简化. 可以将所有给一个元素绑定的事件的事件函数写在一个函数内,通过函数内部的e.type 判断走不同的分支, 避免添加多个函数,占用更多的内存.
//两种时间都调用同一个函数
box1.onmouseover = fn;
box1.onmouseout = fn;
function fn(e) {
e = e || window.event;
// 根据事件类型,执行不同的代码
switch (e.type) {
case "mouseover":
box1.style.backgroundColor = "pink";
break;
case "mouseout":
box1.style.backgroundColor = "yellowgreen";
break;
}
}
取消默认行为和阻止事件传播的方式
• e.preventDefault() 取消默认行为
• e.returnValue 取消默认行为,低版本浏览器使用, 高版本浏览器也能认识
• e.stopPropagation(); 阻止冒泡,标准方式
• e.cancelBubble = true; 阻止冒泡,IE 低版本,(标准中已废弃), 高版本中浏览器也认识
例1 取消默认行为
<body>
<a id="link" href="https://juejin.cn/">点击</a>
<script>
var link = document.getElementById('link');
link.onclick = function (e) {
e = e || window.event;
alert('hello');
// 普通的方式阻止默认行为
return false;
// DOM 的方法
e.preventDefault();
// 低版本浏览器需要使用一个对象的属性
e.returnValue = false;
}
</script>
</body>
例2 阻止冒泡
<body>
<div id="box1">
<div id="box2">
<div id="box3">
</div>
</div>
</div>
<script>
// 事件冒泡
var box1 = document.getElementById('box1');
var box2 = document.getElementById('box2');
var box3 = document.getElementById('box3');
var array = [box1, box2, box3];
for (var i = 0; i < array.length; i++) {
var box = array[i];
box.onclick = function (e) {
e = e || window.event;
console.log(this.id);
// 阻止事件冒泡
e.stopPropagation();
// 低版本浏览器使用属性
e.cancelBubble = true;
}
}
</script>
其他事件类型
MDN web 事件参考:developer.mozilla.org/zh-CN/docs/…
DOM 特效
DOM 提供了一套与元素自身有关的位置和大小的属性。
偏移量属性
• offsetParent 偏移参考父级,距离自己最近的有定位的父级,如果没有定位参考body(html)
• offsetLeft/offsetTop 偏移位置 (如果父元素有定位, 以父元素为参考; 如果父元素没有定位, 参考body)
• offsetWidth/offsetHeight 偏移大小 (指的是元素自身border以内的宽度和高度, 包括width, padding和border)
客户端大小
• client 系列没有参考父级元素。
• clientLeft/clientTop 边框区域尺寸,不常用
• clientWidth/clientHeight 边框内部大小 (不包括border)
滚动偏移属性
• scrollLeft/scrollTop 盒子内部滚动出去的尺寸
• scrollWidth/scrollHeight 盒子内容的宽度和高度(scrollWidth只加了一个内边距, scrollHeight上下两个内边距都加了)
注意:
谷歌浏览器不识别 window.scrollTop, 可以使用它的兼容写法 document.documentElement.scrollTop 来获取.
比如有下面一个结构:
<div id="box">
<p></p>
</div>
它们的属性分别为:
#box {
width: 200px;
height: 200px;
margin: 50px;
border: 30px solid red;
padding: 40px;
background-color: green;
overflow: auto;
}
#box p {
width: 300px;
height: 300px;
background-color: pink;
}
这时候scrollWidth和scrollHeight的值分别为:
console.log(box.scrollWidth);
console.log(box.scrollHeight);
340 = 300 (p的width) + padding-left
380 = 300 (p的width) + padding-top + padding-bottom