1、事件函数
当事件被触发时调用的函数就是事件函数
function fn() {
console.log('我执行了');
}
div.onclick = fn; // fn是一个事件函数
fn(); // fn不是事件函数
事件对象:当一个事件发生的时候,和这个事件有关的一些详细信息保留在一个对象中,这个对象就是事件对象
IE和谷歌:全局的event对象
标准浏览器:事件函数的第一个参数
兼容:IE9及以上,用事件函数的第一个参数,而IE8及以下,用全局的event
var ev = ev || event;
var box = document.getElementById('box');
box.onclick = function (ev) {
// console.log(ev); // 标准浏览器支持的(IE8及以下不支持)
// console.log(event); // IE和谷歌(IE8及以下支持)
var ev = ev || event; // 兼容处理
// console.log(ev);
console.log(ev.type); // 事件类型 click
// 事件源
// console.log(ev.target); // IE8及以下不支持
// console.log(ev.srcElement); // IE8及以下支持
var target = ev.target || ev.srcElement; // 事件源的兼容
target.style.background = 'pink';
console.log(ev.clientX, ev.clientY); // 鼠标相对于可视区的距离
console.log(ev.pageX, ev.pageY); // 鼠标相对于文档的距离(IE8及以下不支持)
console.log(ev.altKey); // 事件发生的时候,alt键是否按下
console.log(ev.ctrlKey); // 事件发生的时候,ctrl键是否按下
console.log(ev.shiftKey); // 事件发生的时候,shift键是否按下
}
2、事件绑定与取消
1、事件绑定
格式:元素.addEventListener(不要on的事件名, 函数, 是否捕获);
格式:元素.attachEvent(要on的事件名, 函数);
<div id="box"></div>
<script>
// 需求:给同一个元素的同一个事件绑定不同的处理函数
var box = document.getElementById('box');
function fn1() {
console.log(1);
console.log(this === window);
}
function fn2() {
console.log(2);
}
// ----------------------------------------
// 之前方法:会覆盖(是一种赋值的写法)
box.onclick = fn1;
box.onclick = fn2;
// ----------------------------------------
// add 添加 Event 事件 Listener监听
// 添加事件监听。第三个参数默认为false(true为捕获,false为冒泡)
// 元素.addEventListener(不要on的事件, 函数, 是否捕获);
// IE8及以下不支持
box.addEventListener('click', fn1, false);
box.addEventListener('click', fn2, false);
// ----------------------------------------
// attach 贴上
// 元素.attachEvent(要on的事件, 函数); 只有冒泡
// IE8及以下支持
box.attachEvent('onclick', fn1);
box.attachEvent('onclick', fn2);
// ----------------------------------------
// 标准浏览器的事件绑定和 ie 浏览器的事件绑定的区别:
// ● ie 没有捕获,标准有捕获
// ● ie 的事件名称前面有 on,标准没有
// ● IE8及以下倒序执行,标准浏览器正序执行
// ● ie 的 this 是 window,标准的是触发这个事件的对象
// ----------------------------------------
// 兼容原理。IE8及以下返回undefined,标准浏览器返回函数
// console.log(box.addEventListener);
if (box.addEventListener) {
// 标准浏览器
box.addEventListener('click', fn1, false);
box.addEventListener('click', fn2, false);
} else {
// IE8及以下
box.attachEvent('onclick', fn1);
box.attachEvent('onclick', fn2);
}
// ----------------------------------------
// 封装一个函数,实现事件绑定的兼容
// 参数:元素 事件 函数
function bind(ele, event, callback) {
if (ele.addEventListener) {
// 标准浏览器
ele.addEventListener(event, callback, false);
} else {
// IE8及以下
ele.attachEvent('on' + event, callback);
}
}
bind(box, 'click', fn1);
bind(box, 'click', fn2);
</script>
2、取消事件绑定
格式:元素.addEventListener(不要on的事件名, 函数, 是否捕获);
解绑:元素.removeEventListener(不要on的事件名, 函数, 是否捕获);
IE8及以下
格式:元素.attachEvent(要on的事件名, 函数);
解绑:元素.detachEvent(要on的事件名, 函数);
<div id="box"></div>
<script>
// 需求:给同一个元素的同一个事件绑定不同的处理函数
var box = document.getElementById('box');
function fn1() {
console.log(1);
}
function fn2() {
console.log(2);
}
// ----------------------------------------
// 之前方法:会覆盖(是一种赋值的写法)
box.onclick = fn1;
box.onclick = null; // 解绑
// ----------------------------------------
// add 添加 Event 事件 Listener监听
// 添加事件监听。第三个参数默认为false(true为捕获,false为冒泡)
// 元素.addEventListener(不要on的事件, 函数, 是否捕获);
// 元素.removeEventListener(不要on的事件, 函数, 是否捕获);
// IE8及以下不支持
box.addEventListener('click', fn1, false);
box.addEventListener('click', fn2, false);
box.removeEventListener('click', fn2, false); // 解绑
// ----------------------------------------
// attach 贴上 detach 分离
// 元素.attachEvent(要on的事件, 函数); 只有冒泡
// 元素.detachEvent(要on的事件, 函数);
// IE8及以下支持
box.attachEvent('onclick', fn1);
box.attachEvent('onclick', fn2);
box.detachEvent('onclick', fn2); // 解绑
// ----------------------------------------
// 封装一个函数,实现事件绑定的兼容
// 参数:元素 事件 函数
function bind(ele, event, callback) {
if (ele.addEventListener) {
// 标准浏览器
ele.addEventListener(event, callback, false);
} else {
// IE8及以下
ele.attachEvent('on' + event, callback);
}
}
// 解绑兼容
function unbind(ele, event, callback) {
if (ele.removeEventListener) {
// 标准浏览器
ele.removeEventListener(event, callback, false);
} else {
// IE8及以下
ele.detachEvent('on' + event, callback);
}
}
bind(box, 'click', fn1);
bind(box, 'click', fn2);
unbind(box, 'click', fn2);
</script>
3、DOM事件流
事件流:当事件发生的时候,事件会按一定的顺序在根节点和各元素节点之间传播,所经过的节点,都会触发对应的事件。
事件流分为三个阶段:
1、捕获阶段:从最外层不具体的元素到具体的元素。document-html-body-box1-box2-box3
2、处于目标阶段:事件到达box3
3、冒泡阶段:从具体的元素到不具体的元素。box3-box2-box1-body-html-document
当事件经过某个元素时,这个元素上恰好绑定着事件,则这个事件就会被触发
html代码:
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
js代码:
var box1 = document.getElementById('box1');
var box2 = document.getElementById('box2');
var box3 = document.getElementById('box3');
function fn() {
console.log(this.id);
}
box1.onclick = fn; // 这种形式的绑定,是在冒泡阶段触发
box2.onclick = fn;
box3.onclick = fn;
2、捕获与冒泡
捕获,事件在子元素发生,先经过父元素,父元素先处理,在分发到子元素
var box1 = document.getElementById('box1');
var box2 = document.getElementById('box2');
var box3 = document.getElementById('box3');
function fn() {
console.log(this.id);
}
// 第三个参数:是否捕获
// false冒泡 true捕获
box1.addEventListener('click', fn, true);
box2.addEventListener('click', fn, true);
box3.addEventListener('click', fn, true);
// 捕获触发可以设置,而冒泡触发是默认的
3、阻止冒泡
标准浏览器:event.stopPropagation();
案例:二级菜单
<button>按钮</button>
<div></div>
<script>
// 需求:点击按钮,div显示,点击页面的任何地方,div隐藏
// Propagationw传播 cancel取消 Bubble泡泡
// 标准浏览器:ev.stopPropagation();
// IE 浏览器:ev.cancelBubble = true;
var btn = document.querySelector('button');
var div = document.querySelector('div');
// 点击按钮,div显示
btn.onclick = function (ev) {
var e = ev || event;
// e.stopPropagation(); // 标准浏览器
// e.cancelBubble = true; // IE8及以下
stopPropagation(e); // 阻止冒泡的兼容,传入的参数是兼容以后的事件对象
div.style.display = 'block';
}
// 点页面的任何地方,div隐藏
document.onclick = function () {
// setTimeout(function () {
div.style.display = 'none';
// }, 2000);
}
// 阻止冒泡的兼容
function stopPropagation(ev) {
if (ev.stopPropagation) {
ev.stopPropagation(); // 标准浏览器
} else {
ev.cancelBubble = true; // IE8及以下
}
}
</script>
某些事件,即赋予了元素特殊的操作
标准浏览器:ev.preventDefault();
IE8及以下:ev.returnValue = false;
通用(要放在函数的最后):return false;
<a href="http://paozha.net">山猫博客</a>
<script>
var a = document.querySelector('a');
a.onclick = function (ev) {
var e = ev || window.event;
// e.preventDefault(); // 标准浏览器支持
// e.returnValue = false; // IE8及以下支持
// preventDefault(e)
return false; // 通用,局限性(必须放在函数的最后)
}
function preventDefault(ev) {
if (ev.preventDefault) {
// 标准浏览器支持
ev.preventDefault();
} else {
// IE8及以下支持
ev.returnValue = false;
}
}
</script>
案例:自定义右键菜单
5、事件委托
事件委托:也叫事件代理,利用事件冒泡原理,只指定一个事件处理程序,就可以管理某一类型的所有事件。
实现:将事件添加到父元素上,当事件发生时,父元素会找到对应触发事件的子元素去处理。好处:后期添加的子元素,依然有这个事件。
好处:
1、新添加的元素也有之前的事件
2、提高性能
html代码:
<ul>
<li>吃饭</li>
<li>睡觉</li>
<li>拉粑粑</li>
</ul>
js代码:
<script>
// 需求:点击li,给它添加背景色
var ul = document.querySelector('ul');
// 之前的做法:循环
// 1、后添加的元素没有之前的事件
// 2、如果元素过多,会耗性能
// var li = ul.querySelectorAll('li');
// for (var i = 0; i < li.length; i++) {
// li[i].onclick = function () {
// this.style.backgroundColor = 'red';
// }
// }
// --------------------------------
// 利用事件代理(事件委托)
// 优点:
// 1、后添加的元素也有之前的事件
// 2、不论子元素多不少个,都只绑定一次事件,节省性能
ul.onclick = function (ev) {
var e = ev || event; // 事件对象的兼容
var target = e.target || e.srcElement; // 事件源的兼容
// console.log(target.nodeName);
// 对事件源进行判断
if (target.nodeName === 'LI') {
target.style.backgroundColor = 'pink';
}
}
// --------------------------------
// 创建一项,添加给ul
var newLi = document.createElement('li');
newLi.innerText = '我是新来的';
ul.appendChild(newLi);
</script>
1、键盘事件
元素.onkeydown 键盘按下
元素.onkeyup 键盘抬起
在能响应用户输入的元素上触发(表单元素、document都可以响应键盘事件)
var input = document.querySelector('input');
// 按下
input.onkeydown = function () {
console.log(this.value);
}
// 抬起
input.onkeyup = function () {
console.log(this.value);
}
var input = document.querySelector('input');
input.onkeydown = function (ev) {
var ev = ev || event;
console.log(ev); // 键盘的事件对象
console.log(ev.key); // 键盘键值(IE8及以下不支持)
console.log(ev.keyCode); // 键码
// a65 z90 空格32 回车13 esc27
console.log(ev.altKey); // 是否按下alt键
console.log(ev.ctrlKey);
console.log(ev.shiftKey);
}
标准和IE:
事件:onmousewheel
方向:ev.wheelDelta 上:120 下:-120
火狐:
事件:DOMMouseScroll 必须用addEventListener绑定
方向:ev.detail 上:-3 下:3
<div id="box"></div>
<script>
// 在box上滚动滚轮,向下滚高度增加,向上滚高度减小
var box = document.getElementById('box');
var h = box.clientHeight; // 获取元素的高
// console.log(h);
bind(box, 'mousewheel', fn); // IE和标准
bind(box, 'DOMMouseScroll', fn); // 火狐
function fn(ev) {
var ev = ev || event;
if (wheelDelta(ev) > 0) {
// 向上
h--;
} else {
// 向下
h++;
}
box.style.height = h + 'px';
}
// 滚轮方向的兼容:向上120 向下-120
function wheelDelta(ev) {
if (ev.wheelDelta) {
// 标准和 IE
return ev.wheelDelta;
} else {
// 火狐
return -40 * ev.detail;
}
}
// 事件绑定
function bind(ele, event, callback) {
if (ele.addEventListener) {
// 标准浏览器
ele.addEventListener(event, callback, false);
} else {
// IE8及以下
ele.attachEvent('on' + event, callback);
}
}
</script>