基本概念:
1. 事件基础:在js中,事件是可以被JS侦测到的行为。
2. 事件函数:当事件被触发时,调用的函数。
// 事件函数:当事件被触发时,调用的函数。
var box = document.getElementsByName('box')[0];
box.onclick = function () {
console.log('hello');
}
//onclick= 后面的函数部分就是事件函数。
3. 事件对象:
- 当事件发生时,浏览器会将事件相关的信息保存到内置的全局对象window.event中,可以直接使用。
注意:有些版本的火狐不支持event属性,返回undefined,所以获取不到事件对象;我这个可能因为我的是最新版本的 你们可以自己测试一下。
document.onclick = function () {
// Chrome浏览器: MouseEvent {isTrusted: true, screenX: 324, screenY: 169, clientX: 324, …}
// IE浏览器:[object MSEventObj]{actionURL: "", ...}
// 火狐浏览器:click { target: html, buttons: 0, clientX: 120, clientY: 103, layerX: 120, layerY: 103 }
console.log(event);
}
- 标准浏览器的事件对象,当事件被触发时候,通过事件函数的第一个参数出入。
// 2. 方式二:
// 标准浏览器的事件对象,当事件被触发时候,通过事件函数的第一个参数出入
document.onclick = function (ev) {
// Chrome浏览器:MouseEvent {isTrusted: true, screenX: 210, screenY: 179, clientX: 210, …}
// IE9及其以上浏览器:[object MSEventObj]{actionURL: "", ...}
// IE8及其以下 不支持 返回undefined
// 火狐浏览器:click { target: html, buttons: 0, clientX: 220, clientY: 36, layerX: 220, layerY: 36 }
console.log(ev);
}
- 兼容的写法
document.onclick = function (ev) {
ev = ev || event;
// Chrome浏览器:MouseEvent {isTrusted: true, screenX: 210, screenY: 179, clientX: 210, …}
// IE浏览器:[object MSEventObj]{actionURL: "", ...}
// 火狐浏览器:click { target: html, buttons: 0, clientX: 220, clientY: 36, layerX: 220, layerY: 36 }
console.log(ev);
}
3.1 事件对象中的属性
-
获取当前触发事件类型;ev.type;
-
获取当前触发的对象;ev.target; 在IE8及其以下写ev.srcElement来获取对象。
-
兼容性获取: var target = ev.target || ev.srcElement;
-
-
获取当前点击的位置,相对于可视区窗口; ev.clientX, ev.clientY
-
获取当前点击的位置,相对于页面; ev.pageX, ev.pageY
-
是否按下了功能键,ev.shiftKey,ev.ctrlKey,ev.altKey
document.onclick = function (ev) {
ev = ev || event;
// 1. 获取当前触发事件类型
console.log(ev.type); //click
// 2. 获取当前触发的对象
// console.log(ev.target === document.documentElement); //html
// console.log(ev.target);
console.log(ev.srcElement === document.documentElement);
// 需要在IE8及其以下写ev.srcElement来获取对象
// 3. 获取当前点击的位置,相对于可视区窗口;
console.log(ev.clientX, ev.clientY);
// 4. 获取当前点击的位置,相对于页面;
console.log(ev.pageX, ev.pageY);
// IE8及其之下不支持
// 5. 是否按下了功能键
console.log(ev.shiftKey); //是否按下了shift键
console.log(ev.ctrlKey); //是否按下了ctrl键
console.log(ev.altKey); //是否按下了alt键
}
事件的绑定
1. 常规的事件绑定的方法
function fn1() {
console.log(1);
}
function fn2() {
console.log(2);
}
box.onclick = function () {
fn1();
}
box.onclick = function () {
fn2();
}
缺点:这种方式事件绑定只能绑定一个事件,点击结果为2。 后面的会覆盖前面的绑定事件
2. 方式二:元素.addEventListener('不加on的事件类型',事件处理函数,是否捕获);
box.addEventListener('click', fn1, false);
box.addEventListener('click', fn2, false);
// 点击结果:1 2
可以实现多个事件的绑定,支持标准浏览器;IE8及其以下不支持;
3. IE8- 的事件绑定 元素.attachEvent('加on的事件类型',事件处理函数);
box.attachEvent('onclick', fn1);
box.attachEvent('onclick', fn2);
// 点击结果 2 1
两者的区别: 元素.addEventListener('不加on的事件类型',事件处理函数,是否捕获)
元素.attachEvent('加on的事件类型',事件处理函数)
- 1. addEventListener 方法比attachEvent多一个是否的捕获的参数;
- 2. addEventListener 的事件类型不需要加on,而且addEventListener 是顺序执行绑定的函数,而attachEvent是倒叙执行;
- 3. addEventListener支持标准的浏览器,attachEvent支持IE8及其以下的浏览器;
- 4. attachEvent事件的事件源始终指向window; addEventListener 指向当前触发事件的对象;
4. 绑定事件的兼容性写法:
function bind(ele, event, callback) {
if (ele.addEventListener) {
ele.addEventListener(event, callback, false);
} else {
ele.attachEvent('on' + event, callback);
}
}
// 调用
bind(box, 'click', fn1);
bind(box, 'click', fn2);
// 标准输出 1 2
// IE8- 输出 2 1
事件的解绑
IE浏览器解绑: 元素.detachEvent(type,function);
标准浏览器解绑:元素.removeEventListener('不加on的事件类型',事件处理函数,是否捕获);
// 解绑事件的兼容性写法
function unbind(ele, event, callback) {
if (ele.removeEventListener) {
ele.removeEventListener(event, callback, false);
} else {
ele.detachEvent('on' + event, callback);
}
}
// 绑定事件的兼容性写法
function bind(ele, event, callback) {
if (ele.addEventListener) {
ele.addEventListener(event, callback, false);
} else {
ele.attachEvent('on' + event, callback);
}
}
// 调用
bind(box, 'click', fn1);
bind(box, 'click', fn2);
unbind(box, 'click', fn2);
// 输出结果 1
事件流
DOM事件流分为3个阶段:事件的捕获阶段,目标阶段,冒泡阶段;
捕获阶段:事件的传播是从不具体的文档传递到具体的执行事件的目标对象;
在绑定事件addEventListener时候最后一个参数为true表示捕获事件;
<div class="box1">
<div class="box2">
<div class="box3"></div>
</div>
</div>
<script>
var box1 = document.querySelector('.box1');
var box2 = document.querySelector('.box2');
var box3 = document.querySelector('.box3');
function fn1() {
console.log(1);
}
// 点击获取事件 捕获
box1.addEventListener('click', fn1, true);
box2.addEventListener('click', fn1, true);
box3.addEventListener('click', fn1, true);
</script>
在执行过程中,单击box3元素,会执行点击事件,首先box1执行,然后将事件向下传递到box2,box3执行点击事件,所以会打印三次1。
目标阶段:通过捕获确定具体触发事件的元素;执行具体的事件函数;
冒泡阶段:事件的传递是从具体的事件目标向父元素传递直到传递给最外层的window;
在JS中,默认是冒泡事件的执行机制;
<div class="box1">
<div class="box2">
<div class="box3"></div>
</div>
</div>
<script>
var box1 = document.querySelector('.box1');
var box2 = document.querySelector('.box2');
var box3 = document.querySelector('.box3');
function fn1() {
console.log(1);
}
// 点击获取事件 不捕获 即使冒泡事件
box1.addEventListener('click', fn1, false);
box2.addEventListener('click', fn1, false);
box3.addEventListener('click', fn1, false);
</script>
在执行过程中,单击box3元素,会执行点击事件,首先自己执行,然后将事件传递到box2,box1都会执行点击事件,所以会打印三次1。
阻止事件冒泡:是指子元素执行事件之后,阻止子元素再给父元素传播事件
- 标准浏览器 ev.stopPropagation();
- IE8- 浏览器 ev.cancelBubble=true;
兼容写法:
// 兼容写法
function stopPropagation(ev) {
ev = ev || event;
if (ev.stopPropagation) {
ev.stopPropagation();
} else {
ev.cancelBubble = true;
}
}
事件默认行为
给一些元素设置一些特殊的操作; 如:a标签默认会跳转页面,右击鼠标会出现菜单。当我们不在需要这些行为的时候 我们我可以阻止事件的默认行为;
阻止事件的默认行为的方式:
- 事件添加的事件,return false;
- 元素.addEventListener的方式阻止 ev.preventDefault();
- 元素.attachEvent 的方式阻止 ev.returnValue = false;
<a href="https://www.baidu.com">百度</a>
<script>
// 事件的默认行为:给一些元素设置一些特殊的操作; a标签默认会跳转页面,右击鼠标会出现菜单
// 当我们不在需要这些行为的时候 我们我可以阻止事件的默认行为;
// 阻止事件的默认行为的方式
// 1. 事件添加的事件,return false;
// 2. 元素.addEventListener的方式阻止 ev.preventDefault();
// 3. 元素.attachEvent 的方式阻止 ev.returnValue = false;
// var a = document.querySelector('a');
var a = document.getElementsByTagName('a')[0];
// a.addEventListener('click', function (ev) {
// ev.preventDefault();
// });
a.attachEvent('onclick', function (ev) {
ev = ev || event;
ev.returnValue = false;
});
</script>
键盘事件
按键按下ev.keypress ev.keydown 按键抬起ev.keyup 按键对应的ASCII码值ev.keyCode, 只有在能影响用户输入的元素和window上面,才会存在键盘事件
// 可以输入任何字符
window.addEventListener('keydown', function (ev) {
console.log(ev.keyCode);
});
// 只能输入字符类的键,不能输入功能键 如ctrl, shift...
window.addEventListener('keypress', function (ev) {
console.log(ev.keyCode);
});
// 按键弹起时候执行
window.addEventListener('keyup', function (ev) {
console.log(ev.keyCode);
});
滚轮事件
鼠标滚轮可以上下滚动,也会被JS监听到,称之为滚轮事件。每个浏览器的标准不同。
- 标准和IE8+浏览器 元素.onmousewheel=函数;
- 火狐浏览器 元素.addEventListener('DOMMouseScroll',执行函数, false);
// 标准和IE8+浏览器
window.onmousewheel = function () {
console.log('滚动了');
}
// 火狐浏览器
window.addEventListener('DOMMouseScroll', function () {
console.log('滚动了');
}, false)
获取滚轮的滚动信息:
- 标准和IE8+浏览器 ev.wheelDelta;
- 火狐浏览器 ev.detail;
// 标准和IE8+浏览器
window.onmousewheel = function (ev) {
ev = ev || event;
// 向下滚动-120
// 向上滚动120
console.log(ev.wheelDelta);
}
// 火狐浏览器
window.addEventListener('DOMMouseScroll', function (ev) {
ev = ev || event;
// 向上滚动 -3
// 向下滚动 3
console.log(ev.detail);
}, false)
兼容性获取滚动值:
// 兼容性写法 获取滚轮事件的信息
function wheelDelta(ev) {
ev = ev || event;
if (ev.wheelDelta) {
// 标准浏览器和IE8+浏览器
return ev.wheelDelta;
} else {
// 火狐浏览器
return ev.detail * -40;
}
}
事件委托
又称事件代理, 事件委托就是利用事件冒泡,只指定一个事件处理函数,就可以管理某一类型的所有事件。
实现:将事件添加到父元素身上,当事件发生的时候,父元素会去找对应触发事件的子元素即ev.target/ev.srcElement去处理。
好处:1、节省性能,不需要给每个子元素绑定事件;2、新添加的元素也动态的绑定了之前的事件
案例:利用事件委托,点击li,给对应的li添加背景
<ul id="list">
<li>11111</li>
<li>22222</li>
<li>33333</li>
<li>44444</li>
<li>55555</li>
</ul>
<script>
var ul = document.getElementById('list');
var li = ul.getElementsByTagName('li');
// 事件委托
ul.onclick = function (ev) {
var ev = ev || event;
var target = ev.target || ev.srcElement;
if (target.nodeName === 'LI') {
target.style.backgroundColor = 'skyblue';
}
}
// 新加元素
var newLi = document.createElement('li');
newLi.innerHTML = '新事件';
ul.appendChild(newLi);
</script>