在 JavaScript 中,事件处理是网页交互的核心。事件是用户与页面交互时发生的行为,比如点击、滚动、鼠标移动等操作。JavaScript 提供了一套完整的事件模型,包括事件对象、事件监听、事件委托等功能,用于实现页面交互和响应用户行为。
- 事件对象:
- 当事件发生时,会自动生成一个事件对象(Event Object),该对象包含了与事件相关的信息,比如事件类型、触发元素、鼠标位置等。
- 开发者可以通过事件对象来获取这些信息,并根据其执行相应的操作。
- 监听事件:
- 监听事件是指为 HTML 元素绑定一个或多个事件处理函数,当事件触发时,该函数会被调用。
- 常见的事件包括 click、mousedown、mouseup、mousemove、keydown、keyup 等等。
- 监听事件的方法有多种,最常用的是 addEventListener() 和 attachEvent() 方法。
- 事件委托:
- 事件委托是一种将事件处理从子元素传递到父元素的技术,可以提高性能和代码可维护性。
- 委托的原理是利用事件冒泡机制,在父元素上监听事件,然后根据事件目标元素的不同执行不同的操作。
- 通过事件委托,可以减少事件处理器的数量,避免重复绑定事件,同时也能够应对动态添加或删除元素的情况。
二十一、event事件
1.1 event 事件对象
当事件触发的时候产生的对象,存储着和事件相关的信息
chrome、firefox、IE9+等:事件函数的第一个形参就是事件对象
document.onclick = function(e){
alert( e );
};
chrome、IE8以下:全局变量 event
document.onclick = function(){
alert( event );
};
兼容
document.onclick = function(ev){
ev = ev || window.event;
};
那么,在event事件对象里面有哪些信息呢?我们一起来看一下
1.2 相对于窗口的位置
- ev.clientX 存储鼠标相对于窗口的水平坐标
- ev.clientY 存储鼠标相对于窗口的垂直坐标
1.3 相对于文档的位置
- ev.pageX 存储鼠标相对于文档的水平坐标(不兼容IE8及以下)
- ev.pageY 存储鼠标相对于文档的垂直坐标(不兼容IE8及以下)
IE8以及以下
ev.clientY + document.documentElement.scrollTop || ev.pageY
1.4 ev.button
- 0------按下左键
- 1------按下滚轮键
- 2------按下右键
document.onmousedown = function (ev) {
ev = ev || window.event;
alert(ev.button)
}
1.5 oncontextmenu
返回false表示屏蔽右键菜单
document.oncontextmenu = function () {
return false;
}
那么,有什么用呢?我们可以结合鼠标按键先屏蔽掉默认的右键菜单然后自己去定义
1.6 onselectstart
文本不能被选中
document.onselectstart = function () {
return false;
}
也可以
<html lang="en" onselectstart="return false">
我们之前也讲过一个css3的属性
user-select: none;
1.7 ev.keyCode键值:
1.7.1 键盘事件
按下
document.onkeydown = function () {
}
一直按 同时存在的时候down 优先于press
document.onkeypress = function () {
}
键盘抬起
document.onkeyup = function () {
}
1.7.2 ev.keyCode键值
键盘上每个键都对应着一个数值
document.onkeydown = function (ev) {
ev = ev || window.event;
console.log(ev.keyCode);
}
1.8 表单事件
1.8.1 checked
在js里面,单选或者复选框里面的checked属性会被强制转换为布尔值
我们默认的不给checked写实际上就是给了checked="checked"
var oInput = document.getElementById('input');
console.log(oInput.checked); //true
等价
oInput.checked = "checked";
console.log(oInput.checked); //true
给的值会被强制转换为Boolean值,因此我们直接写布尔值效率要高很多
oInput.checked = false; //如果我们给他false就表示不选中
1.8.2 获取失去焦点
获取焦点
inp.onfocus = function () {
console.log('获取焦点');
}
也可以用函数直接运行,当页面刷新的时候就处于获取焦点的状态
obj.focus()
失去焦点
inp.onblur = function () {
console.log('失去焦点');
}
也可以用函数直接运行,当页面刷新的时候就处于获取焦点的状态
obj.blur();
1.8.3 onchange
当表单内容发生改变的时候触发
- text 当内容改变的时候失去焦点触发
- radio 选中变成非选中触发
- checkbox 选中变成非选中触发
- select 选中内容改变的时候
1.8.4操作下拉列表
<select name="" id="">
<option value="1">111</option>
<option value="2">222</option>
<option value="3">333</option>
</select>
sel.onchange = function () {
var value = this.options[this.selectedIndex].text; //获取option标签里面的内容
console.log(value);
console.log(this.value); //获取value里面的值
}
其中:
this.selectedIndex
是对应的option标签的索引值.text
也可以表示为.innerHTML
表示获取里面的内容
1.9 滚轮事件
1.9.1 滚轮事件兼容
谷歌和IE浏览器
document.onmousewheel = function(){
console.log(1);
};
火狐浏览器
document.addEventListener('DOMMouseScroll',function () {
console.log(1);
});
兼容:
function mousewheel(obj , eFn) {
document.onmousewheel===null?obj.onmousewheel=eFn:obj.addEventListener('DOMMouseScroll',eFn);
}
当谷歌和IE的时候是支持onmousewheel的,但是这个时候没有绑定事件函数那么值就是null空对象,这个时候我们再将eFn赋值给他,当不支持onmousewheel的时候为undefined则添加addEventListener
1.9.2 e.wheelDelta
在chrome和IE里,12 或者 3的倍数,负值代表向下滚轮(贴近胸),正值代表向上滚轮(往上推)
console.log(e.wheelDelta);
在firefox里,3的倍数,负值代表向上滚轮(往上推),正值代表向下滚轮(贴近胸)
console.log(e.detail);
兼容:
判断delta的正负就可以知道向上滚轮还是向下滚轮(向前正,向后负)
var delta = e.wheelDelta/12 || -e.detail/3;
除以他们的倍数是为了可以明确的知道滚了多少次了
1.10 ev.cancelBubble冒泡
<div class="box1">
<div class="box2">
<div class="box3"></div>
</div>
</div>
oBox1.onclick = daGOu;
oBox2.onclick = daGOu;
oBox3.onclick = daGOu;
function daGOu() {
alert(this.className);
}
当执行的时候我们会发现,点击box2的时候会执行box2的事件也会执行box1的事件,点击box3的时候,会执行box1,box2,box3的事件,我们可以看出,就好像从内到外冒泡一样的,那么我们怎么去解决呢?
阻止冒泡
ev.cancelBubble = true 浏览器都可以但是不符合W3C标准 (是一个属性)
ev.stopPropagation() 适用于chrome fireFox 不支持IE 符合W3C标准 (是一个方法)
oBox1.onclick = daGOu;
oBox2.onclick = daGOu;
oBox3.onclick = daGOu;
function daGOu(ev) {
ev = ev || window.event;
ev.cancelBubble = true;
alert(this.className);
}
二十二、添加事件监听
1.1 添加事件
1.1.1 传统添加事件
在网站的开发和维护中,给一个对象绑定事件以后我们不方便再去改变他,那么如果我们还要想给他添加新事件的时候,如果我们用以前的添加事件的方式去添加
oBox.onclick = function(){
alert( 1 );
};
oBox.onclick = function(){
alert( 2 );
};
这样子后面添加的事件会把前面的覆盖掉
为了避免不覆盖原来的,我们就要用到新的注册事件的方式。
1.1.2 添加事件监听
- 主流浏览器写法(去掉on的事件名 , 事件函数,布尔值【可以不写】 默认false)
oBox.addEventListener('click' , function(){
alert('1');
} , false);
oBox.addEventListener('click' , function(){
alert('2');
} , false);
- IE8及以下写法
oBox.attachEvent( 'onclick' , function(){
alert( 1 );
} );
oBox.attachEvent( 'onclick' , function(){
alert( 2 );
} );
- 兼容写法
document.addEventListener?obj.addEventListener(eName,eFn):obj.attachEvent('on'+eName , eFn);
};
addEvent( oBox,'click' , function(){
alert( 1 );
} );
addEvent( oBox,'click' , function(){
alert( 2 );
} );
1.2 解绑事件
1.2.1传统事件的解绑
oBox.onclick = function(){
alert(1);
};
oBox.onclick = null;
1.2.2 监听事件解绑
oBox.addEventListener('click' , function(){
alert('1');
} , false);
oBox.removeEventListener('click' , function(){
alert('1');
});
但是,我们可以发现这样子是解绑不了的,因为函数是引用类型,不仅比较值,还要比较内存地址不相等的。
所以,我们只能这样子
IE8以上:
oBox.addEventListener('click' , fn2);
oBox.removeEventListener('click' , fn2);
function fn2(){
alert('2');
};
也就是三个对应:
- 事件名对应
- 事件函数要对应
- 布尔值要对应
IE8以下:
oBox.detachEvent('onclick' , fn2);
1.2.3 添加和解绑事件兼容:
function addEvent(obj,eName,eFn) {
if(obj.arr){
obj.arr.push(eFn); //数组里面有值以后就把后面添加的函数push进去就行了
}else{
obj.arr = [eFn]; //自定义一个属性,将函数存进去
}
obj.addEventListener ? obj.addEventListener(eName,eFn) : obj.attachEvent('on'+eName,eFn);
}
function removeEvent(obj,eName,eFn) {
if(eFn){
for( var i=0; i<obj.arr.length; i++ ){
if(obj.arr[i] + '' === eFn + ''){//将存起来的函数都和remove里面的函数换成字符串进行比较,如果相等,就解绑这一个函数
obj.removeEventListener ? obj.removeEventListener(eName,obj.arr[i]) : obj.detachEvent('on'+eName,obj.arr[i])
}
}
}else{
for( var i=0; i<obj.arr.length; i++ ){
obj.removeEventListener ? obj.removeEventListener(eName,obj.arr[i]) : obj.detachEvent('on'+eName,obj.arr[i]);
}
}
}
二十三、事件委托
1.1 小案例
我们先做一个小案例,在box大盒子中有几个小盒子,点击的时候会变成粉红色。当点击添加按钮的时候,会在后面添加新的盒子,并且点击添加的小盒子也能变成粉红色
怎么样去实现这个功能呢?
第一步:需要给里面所有小盒子添加点击事件
for( var i=0; i<aP.length; i++ ){
aP[i].addEventListener('click',function () {
this.style.background = 'deeppink';
})
}
第二步:当点击按钮的时候,增加小盒子,也就是我们要创建节点,但是小盒子的点击事件在之前就添加了的,后面添加的小盒子并没有被注册点击事件,这时候就需要我们在注册一遍点击事件。
oBtn.onclick = function () {
var p = document.createElement('p'); //在dom中创建节点
p.innerHTML = ++n;
p.addEventListener('click',function () {
this.style.background = 'deeppink';
});
oBox.appendChild(p); //将创建的节点添加到box盒子里面
}
1.2 认识事件委托
事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
oBox.addEventListener('click',function (e) {
e = e || window.event;
console.log(e.currentTarget); //添加监听的那个对象(当前对象)
console.log(e.target); //点击的对象(目标对象)
})
1.3用事件委托解决小案例
oBox.addEventListener('click',function (e) {
e = e || window.event;
if(e.target.tagName === 'P')e.target.style.background = 'deeppink';
});
oBtn.addEventListener('click',function () {
var p = document.createElement('p');
p.innerHTML = ++n;
oBox.appendChild(p);
})
【上一篇】JavaScript精粹(五)- DOM&BOM&offset
【下一篇】JavaScript精粹(七)- 正则表达式