发展
事件监听 定义了部分JavaScript与网页元素的关系,但是元素被加载和卸载并不会自动添加和回收监听器,所以JavaScript程序员需要
- 注册事件
- 在视图卸载之前移出监听,防止残留内存
JavaScript与HTML的交互是通过事件实现的,事件代表文档DOM或浏览器窗口BOM中某个有意义的动作。抽象来看,这运用了软件工程的一种设计模型-观察者模型
- 事件最早在IE3和Netscape Navigator 2出现,当时的目标是把某些表单处理工作从服务器转移到浏览器上。
- 点击button,也意味着点击button的容器、整个页面...,事件流描述了页面接受事件的顺序
- IE8是最后一个使用专有事件系统的主流浏览器
- DOM2开始标准化DOM事件API——DOM2 Event,目前所有浏览器基本都实现了DOM2的核心内容
- BOM和DOM都有事件,HTML5致力于明确BOM与DOM的关系
- DOM3又新增了一系列事件
DOM2 Event规定事件流分为3个阶段,event.eventPhase数字标记:事件捕获1、到达目标2、事件冒泡3
创建事件处理程序(监听器)
- 特定元素支持的事件,可以用HTML属性的形式指定处理程序,例如button的onclick。处理程序中可以通过this访问元素【不推荐:JavaScript与HTML强耦合】
<button onclick="console.log(&quto;转义双引号&quto;)"/>
- DOM0:使用JavaScript获得元素,然后赋值来注册监听。btn.onclick=null移出监听
- DOM2:addEventListener(事件名,处理程序,是否在捕获阶段调用)、removeEventListener传入与前者相同的参数即可移除监听【匿名函数作为事件处理程序时候,无法移除监听】【拦截事件:将处理程序注册到捕获阶段】
- IE:【只支持冒泡阶段】attachEvent(事件名,处理程序)、detachEvent
- addEventListener函数的第三个参数可以是布尔值,也可以是对象-拥有下列属性:
capture: Boolean 表示listener会在该类型的事件捕获阶段传播到该EventTarget时触发。once: Boolean 表示listener 在添加之后最多只调用一次。如果是true,listener会在其被调用之后自动移除。passive: Boolean 设置为true时,表示listener永远不会调用preventDefault()。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。
使用元素属性赋值注册监听的方式btn.onclick,有缺点即事件目标对每种事件只有一种处理程序。然而使用addEventListener,不会重写之前的注册程序,同时存在,按注册顺序调用
事件对象
- Firefox/Google:在DOM中发生事件,生成一个event对象
- Opera/IE:event是全局变量,window.event
注意:IE中事件发生的对象是window.event.srcElement
对象包含了一些基本信息:导致事件的元素,事件的类型、以及相关数据(鼠标点击位置、按键...)
所有事件对象都包括以下公共属性(只读)和方法(只读):
- currentTarget 处理程序所在元素 处理程序内部,this的值
- target事件目标(绑定事件那个dom)
- bubbles 是否冒泡
- cancelable 是否可以取消默认行为
- defaultPrevented 是否已经调用了preventDefault(DOM3新增)
- eventPhase 调用事件处理程序的阶段:1 捕获;2 处于阶段;3 冒泡阶段
- detail 整数类型 事件相关的其他信息
- view 与事件关联的抽象视图,==发生事件的window对象,类型是AbstractView
- trusted true表明是系统的即浏览器生成的,false为开发人员JavaScript自定义的(DOM3新增)
- type 事件类型,例如click、mouseover等一个处理程序处理多种事件,case语句分情况
- preventDefault() 取消事件默认行为,cancelable是true时可以使用【特定事件的默认行为,e.g:链接被单击时候导航到href指定的URL】
- stopPropagation() 取消事件流的后续捕获/冒泡,bubbles为true才能使用
- stopImmediatePropagation() 阻止该事件目标执行别的注册事件(DOM3新增)
区别target与currentTarget:
<body onclick="处理事件“>
<button>
</button>
</body>
处理程序中:
this== currentTarget即处理程序所属的元素
target==button
事件
DOM3事件
DOM3定义了如下事件:
-
用户界面事件UIEvent:与BOM交互的通用浏览器事件
-
焦点事件FocusEvent:获取或失去焦点
-
鼠标事件MouseEvent:使用鼠标在页面上执行某些操作
-
滚轮事件WheelEvent:使用鼠标滚轮或类似设备
-
输入事件InputEvent:
-
键盘事件KeyboardEvent
-
合成事件CompositionEvent:使用某种IME(输入法编辑器)输入字符时触发
-
用户界面HTMLEvents一般dom事件
-
变化事件 ~~MutationEvents,一般化dom变动 ~~Deprecated
用户界面事件HTMLEvent
DOMActivate
- load:window【页面的外部资源加载完成、对应body元素】、frameset、img元素上存在,元素加载完成后触发\
- unload:同load,卸载触发,一般用于清理内存
- abort:加载完成前被用户提前终止下载时触发
- resize窗口或者窗格被缩放时触发
- scroll用户滚动包含滚动条的元素时
img即使不添加到DOM,只要给它设置了src属性就会立即开始下载
状态变化事件
- DOM树构建完成后立即触发DOMContentLoaded事件,不用等图片、
- JavaScript文件、CSS文件或其他资源文件。
- 不支持DOMContentLoaded事件的,用超时为0的setTimeout()函数来设置处理程序。
- 其他外部资源加载成功之后,触发window的load事件。
- 支持readystatechange事件的每个对象都有一个readyState属性,属性值可能是uninitialized、loading、loaded、interactive、complete.
焦点事件
blur:失去焦点触发,不冒泡 focus focusin:冒泡般
鼠标和滚轮
- mousewheel:用户使用滚轮会在任何元素上触发wheelDelta+-120
- click:单击鼠标主键或是键盘回车
- dbclick:双击
- mousedown:任意鼠标键
- mouseup:释放鼠标键触发
- mouseover:从元素外部到元素内部
- mouseenter:鼠标光标从元素外移到内
- mouseleave:
- mousemove:元素上移动时反复触发
- mouseout:从一个元素A到另一个B,在A触发,B是相关元素relatedTarget
事件之间存在包含关系,所以规定双击的触发顺序是
- mousedown
- mouseup
- click//触发依赖前两,如果前两个事件被取消就不触发
- mousedown
- mouseup
- click
- dbclick
修饰键 shift、ctrl、alt、meta,DOM规定了四个属性,用布尔值来标记修饰键状态,
if(event.shiftKey){
keys.push("shift");
}
键盘与输入
- keydown:长按重复触发
- keypress:产生字符后,长按重复触发
- keyup
- event.keyCode=键码
合成事件
处理IME输入时的复杂输入序列,IME可以让用户输入物理键盘上没有的字符
compositionstart、compositionupdate 、compositionend
除了浏览器定义的常见用户事件,也支持程序员自定义合成事件
let stEvent = new Event('start');
const onStart = function(event){
// 自定义
}
// 注册监听
document.addEventListener('start', onStart);
// 触发
document.dispatchEvent(stEvent);
// 事件监听会占用内存
document.removeEventListener('start', onStart);
HTML5事件
- contextmenu
- beforeunload
- DOMContentLoaded
- windows是右击鼠标,mac单击+ctrl
<!DOCTYPE html>
<html>
<head>
<title>ContextMenu Event</title>
<script>
window.addEventListener("load",(event)=> {//页面加载之后注册监听
let div=document.getElementById("my");
div.addEventListener("contextmenu",(event)=>{//展示菜单
event.preventDefault();
let menu=document.getElementById("menu");
menu.style.left=event.clientX+"px";
menu.style.top=event.clientY+"px";
menu.style.visibility="visible";
});
document.addEventListener("click",(event)=>{//随便点击页面的部分
document.getElementById("menu").style.visibility="hidden";
});
});
</script>
</head>
<body>
<div id="my">任何位置,右击鼠标或ctrl+单击显示菜单栏</div>
<ul id="menu" style="position:absolute;visibility:hidden;">
<li>1</li>
<li>1</li>
<li>1</li>
</ul>
</body>
</html>
模拟事件
事件除了用户交互或浏览器功能触发,通过JavaScript也可以模拟事件发生
// 创建
let myEvent = document.createEvent('MouseEvents');
// 初始化 事件对象
myEvent.initMouseEvent('click',true,true,document.defaultView,0,0...);
// 触发事件
btn.dispatchEvent(myEvent);