10. 常用的事件

什么是事件?

文档(html元素及document)或者浏览器的窗口发生的一些特定的交互瞬间;可以监听这些事件,来实现在事件发生时执行特定的操作;

元素天生自带的默认行为,不论我们是否给其绑定了方法,当我们操作的时候,也会把对应的事件触发;

let btn = document.querySelector('.btn');
let box = document.querySelector('.box');

常用的事件行为

[鼠标事件]

  • click 点击(移动端click被识别为单击)
  • dblclick 双击
  • mousedown 鼠标按下
  • mouseup 鼠标抬起
  • mousemove 鼠标移动
  • mouseover 鼠标滑过
  • mouseout 鼠标滑出
  • mouseenter 鼠标进入
  • mouseleave 鼠标离开
  • onmousewheel 鼠标滚轮滚动

[键盘事件]
一般input、textarea、document.body、document、window、document.documentElement 监听键盘事件

  • keydown 按下某个键
  • keyup 抬起某个键
  • keypress 除Shift/Fn/CapsLock键以外,其它键按住(连续触发)
let input = document.querySelector('#input');
input.onkeydown = function () {
   console.log('123')
};
document.onkeyup = function () {
   console.log('keyup')
};
window.onkeydown = function () {
   console.log('window key down')
};

/=>键盘事件对象
code & key:存储的都是按键,code更细致   // code: "KeyF"   key: "F"  
keyCode & which:存储的是键盘按键对应的码值  // keyCode: 70  which: 70
方向键:37 38 39 40 =>左上右下 
空格SPACE 32
回车ENTER 13
回退BACK 8
删除DEL 46
SHIFT 16
CTRL 17
ALT  18

[移动端手指事件]

  • touchstart 手指按下
  • touchmove 手指移动
  • touchend 手指松开
  • touchcancel 操作取消(一般应用于非正常状态下操作结束)

多手指事件模型 Gesture

  • gesturestart
  • gesturechange / gestureupdate
  • gestureend
  • gesturecancel

[表单元素常用事件]

oninput input、textarea 等元素的输入事件

  • onfocus 获取焦点(光标)事件
  • onblur 失去焦点时触发
  • onchange 事件,表单的值(value)发生改变时触发
input.onfocus = function () {
   console.log('获取焦点')
};
input.onblur = function () {
   console.log('失去焦点')
};
input.oninput = function () {
   console.log(this.value);
};

[系统事件]

  • window.onload 页面中所有的资源全部加载完触发
  • window.onresize 当前窗口尺寸发生改变时触发
  • window.onsroll 滚动条滚动时触发
  • unload 资源卸载
  • beforeunload 当前页面关闭之前
  • error 资源加载失败
  • scroll 滚动事件
  • readystatechange AJAX请求状态改变事件
  • contextmenu 鼠标右键触发
window.onresize = function () {
   console.log('变了、变了');
};

[音视频常用事件]

  • canplay 可以播放(资源没有加载完,播放中可能会卡顿)
  • canplaythrough 可以播放(资源已经加载完,播放中不会卡顿)
  • play 开始播放
  • playing 播放中
  • pause 暂停播放

DOM0

元素.on事件行为 = function(){}

DOM0事件绑定的原理:

给元素的私有属性赋值,当事件触发,浏览器会帮我们把赋的值执行,但是这样也导致 “只能给当前元素某一个事件行为绑定一个方法”

box.onclick = function () {console.log('哈哈哈')};
box.onclick = function () {console.log('呵呵呵')};
// 每次点击只输出呵呵呵
清除直接设置为null即可
box.onclick = function () {console.log('呵呵呵')
    box.onclick = null;
};

box.onclick = function () {
    console.log('哈哈哈~~');
    //=>移除事件绑定:DOM0直接赋值为null即可
    box.onclick = null;
} 

DOM2

事件绑定:
   ele.addEventListener('不带on的事件名',函数,是否捕获)

事件解除:(重要的是解除绑定)
   ele.removeEventListener('不带on的事件名',有名函数(和绑定函数一个地址),是否捕获)

DOM2事件绑定的原理:

基于原型链查找机制,找到EventTarget.prototype上的方法并且执行,此方法执行,会把给当前元素某个事件行为绑定的所有方法,存放到浏览器默认的事件池中(绑定几个方法,会向事件池存储几个),当事件行为触发,会把事件池中存储的对应方法,依次按照顺序执行 “给当前元素某一个事件行为绑定多个不同方法”

box.addEventListener('click', function () {
    console.log('哈哈哈~~');
}, false);
box.addEventListener('click', function () {
    console.log('呵呵呵~~');
}, false);
点击一次,输出2次内容   哈哈哈~~     呵呵呵~~
    
//DOM2事件绑定的时候,我们一般都采用实名函数
//>目的:这样可以基于实名函数去移除事件绑定
    function fn() {
    console.log('哈哈哈~~');
    //=>移除事件绑定:从事件池中移除,所以需要指定好事件类型、方法等信息(要和绑定的时候一样才可以移除)
    box.removeEventListener('click', fn, false);
}
box.addEventListener('click', fn, false);  

//false表示在冒泡阶段执行此方法,true表示在捕获阶段执行此方法,默认为false
DOM0只能在目标阶段和冒泡阶段触发执行;
DOM2可以控制在捕获阶段触发;

练习一下

function fn1() { console.log(1); }
function fn2() { console.log(2); }
function fn3() { console.log(3); }

function fn1() { console.log(1); }
function fn2() { console.log(2); }
function fn3() { console.log(3); }

box.onclick = fn1
box.onclick = fn2   
box.addEventListener('click', fn2, false);
box.addEventListener('click', fn3, true);
box.addEventListener('click', fn1, false);
box.onclick = function(){console.log('哈哈哈~');}
box.addEventListener('click', fn2, true);
//=>基于addEventListener向事件池增加方法,存在去重的机制 “同一个元素,同一个事件类型,在事件池中只能存储一遍这个方法,不能重复存储”
box.addEventListener('click', fn1, false);
box.addEventListener('mouseover', fn1, false); 
box.addEventListener('click', function () {
    console.log('哔咔哔咔~~');
});
box.onclick = function () {
    console.log('哇咔咔~~');
}
box.addEventListener('click', function () {
    console.log('call~~');
});

/* DOM0中能做事件绑定的事件行为,DOM2都支持;DOM2里面一些事件,DOM0不一定能处理绑定,例如:transitionend、DOMContentLoaded... */
box.style.transition = 'opacity 1s';
box.ontransitionend = function () {
    console.log('哇咔咔~~');
}
box.addEventListener('transitionend', function () {
    console.log('哇咔咔~~');
}); 

window.onload VS $(document).ready()有什么区别

window.addEventListener('load', function () {
    //=>所有资源都加载完成触发
    console.log('LOAD');
});
window.addEventListener('DOMContentLoaded', function () {
    //=>只要DOM结构加载完就会触发
    console.log('DOMContentLoaded');
});

$(document).ready(function(){})
$(function () {
    //=>JQ中的这个处理(DOM结构加载完触发)采用的就是DOMContentLoaded事件,并且依托DOM2事件绑定来处理,所以同一个页面中,此操作可以被使用多次
});

//JQ中的事件绑定采用的都是DOM2事件绑定,例如:on/off/one */
let $box = $('#box');
$box.one('click', function () {
    console.log('哇咔咔~~');
}); 
$box.on('click', function () {
    console.log('哇咔咔~~');
});
$box.on('click', function () {
    console.log('哔咔哔咔,丘~~');
});

1、$(document).ready() 采用的是DOM2事件绑定,监听的是DOMContentLoaded 这个事件,所以只要DOM结构加载完成就会被触发执行,而且同一个页面中可以使用多次(绑定不同的方法,因为基于DOM2事件池绑定机制完成的);

2、window.onload必须等待所有资源都加载完成才会被触发执行,采用DOM0事件绑定,同一个页面只能绑定一次(一个方法),想绑定多个也需要改为window.addEventListener('load', function () {})DOM2绑定方式;

事件对象和事件传播机制

给元素的事件行为绑定方法,当事件行为触发方法会被执行,不仅被执行,而且还会把当前操作的相关信息传递给这个函数 =>“事件对象”

  • 如果是鼠标操作,获取的是MouseEvent类的实例 =>鼠标事件对象
  • 鼠标事件对象 -> MouseEvent.prototype -> UIEvent.prototype -> Event.prototype -> Object.prototype
  • 如果是键盘操作,获取的是KeyboardEvent类的实例 =>键盘事件对象
  • 除了以上还有:普通事件对象(Event)、手指事件对象(TouchEvent)等

事件对象和函数以及给谁绑定的事件没啥必然关系,它存储的是当前本次操作的相关信息,操作一次只能有一份信息,所以在哪个方法中获取的信息都是一样的;第二次操作,存储的信息会把上一次操作存储的信息替换掉...;

每一次事件触发,浏览器处理机制

  1. 捕获到当前操作的行为(把操作信息获取到),通过创建MouseEvent等类的实例,得到事件对象EV
  2. 通知所有绑定的方法(符合执行条件的)开始执行,并且把EV当做实参传递给每个方法,所以在每个方法中得到的事件对象其实是一个
    ......
  3. 后面再重新触发这个事件行为,会重新获取本次操作的信息,用新的信息替换老的信息,然后继续之前的步骤...
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342