共计 20878 个字符,预计需要花费 53 分钟才能阅读完成。
JavaScript 与 HTML 的交互是通过 事件 实现的,事件代表文档或浏览器窗口中某个有意义的时刻。
能够应用仅在事件产生时执行的 监听器(即处理程序)订阅事件。=> 观察者模式 => 页面行为(JavaScript 中定义)与页面展现(HTML 和 CSS 定义)的拆散。
最早的事件是为了把某些表单解决工作从服务器转移到浏览器上来。DOM2 开始尝试以合乎逻辑的形式来标准化 DOM 事件。IE8 是最初一个应用专有事件零碎的支流浏览器。
事件流
页面哪个局部领有特定的事件呢?当你点击一个按钮时,实际上不光点击了这个按钮,还点击了它的容器以及整个页面。
事件流 形容了页面接管事件的程序。
IE 反对事件冒泡流,Netscape Communicator 反对事件捕捉流
事件冒泡
从最具体的元素开始触发,而后向上流传至没有那么具体的元素(document)。
点击事件:被点击的元素最先触发 click 事件,而后 click 事件沿 DOM 树一路向上,在通过的每个节点上顺次触发,直至达到 document 对象。
古代浏览器中的事件会始终冒泡到 window 对象。
事件捕捉
最不具体的节点(document)最先收到事件,而最具体的节点最初收到事件。=>为了在事件达到最终目标前拦挡事件。
点击事件:最先由 document 元素捕捉,而后沿 DOM 树顺次向下流传,直至达到理论的指标元素。
古代浏览器都是从 window 对象开始捕捉事件。DOM2 Events 标准规定的是从 document 开始。
因为旧版本浏览器不反对,通常倡议应用事件冒泡,非凡状况下能够应用事件捕捉。
DOM 事件流
DOM2 Events 标准规定事件流分为 3 个阶段:事件捕捉、达到指标和事件冒泡。
- 事件捕捉:最先产生,为提前拦挡事件提供了可能;
- 理论的指标元素接管到事件;
- 冒泡:最迟要在这个阶段响应事件。
在 DOM 事件流中,理论的指标在捕捉阶段不会接管到事件。下一阶段会在理论指标元素上触发事件的“达到指标”阶段,通常在事件处理时被认为是冒泡阶段的一部分;而后冒泡阶段开始,事件反向流传至文档。
尽管 DOM2 Events 标准明确捕捉阶段 不命中 事件指标,但古代浏览器都会在捕捉阶段在事件指标上触发事件。=> 在事件指标上有两个机会来处理事件。
所有古代浏览器都反对 DOM 事件流,只有 IE8 及更早版本不反对。
capture phase | | / \ bubbling up
-----------------| |--| |-----------------
| element1 | | | | |
| -------------| |--| |----------- |
| |element2 \ / | | | |
| -------------------------------- |
| W3C event model |
------------------------------------------
事件处理程序
事件是用户或浏览器执行的某种动作。如 click、load 等。
为响应事件而调用的函数被称为 事件处理程序 (或 事件监听器)。事件处理程序的名字以“on”结尾。
有多种形式能够指定事件处理程序。
HTML 事件处理程序
特定元素反对的每个事件都能够应用 事件处理程序的名字(onxxx)以 HTML 属性的模式来指定。此时属性的值必须是可能执行的 JavaScript 代码。
因为属性的值是 JavaScript 代码,所以不能在未经本义的状况下应用 HTML 语法字符,如 &、”、< 和 >。为防止应用 HTML 实体,能够应用单引号代替双引号,或者应用 \"。
在 HTML 中定义的事件处理程序能够蕴含准确的动作指令,也能够调用在页面其余中央定义的脚本。作为事件处理程序执行的代码能够拜访全局作用域中的所有。
以这种形式指定的事件处理程序有 一些非凡的中央:
- 会创立一个函数来封装属性的值。这个函数有一个非凡的局部变量 event,即 event 对象;
- 在这个函数中,this 值相当于事件的指标元素;
-
这个动态创建的包装函数,其作用域链被扩大了。=> document 和元素本身的成员都能够被当成局部变量来拜访。这是通过应用 with 实现的。
// 实际上的包装函数是 onclick 属性的值 function () {with(document) {with(this) {// ... HTML 事件处理程序属性值} } }
=> 事件处理程序能够更不便地拜访本人的属性(不必带 this.)
如果元素是一个表单输入框,则作用域链中还会蕴含表单元素 => 事件处理程序的代码能够不用援用表单元素,而间接拜访同一表单中的其余成员了(通过 name 属性)。
在 HTML 中指定事件处理程序 存在的问题:
-
机会问题。有可能 HTML 元素曾经显示在页面上,但事件处理程序的代码还无奈执行。=> 大多数 HTML 事件处理程序会封装在 try/catch 块中,以便在这种状况下静默失败。
<input type="button" value="Click Me" onclick="try{doSomething();}catch(ex){}">
- 对事件处理程序作用域链的扩大在不同浏览器中可能导致不同的后果。不同 JavaScript 引擎中标识符解析的规定存在差别 => 拜访有限定的对象成员可能导致谬误。
- HTML 与 JavaScript 的强耦合。(如果要批改,必须在 HTML 和 JavaScript 中都批改代码)
DOM0 事件处理程序
把一个函数赋值给(DOM 元素的)一个事件处理程序属性。=> 简略
要应用 JavaScript 指定事件处理程序,必须先获得要操作对象的援用。
每个元素(包含 window 和 document)都有通常小写的事件处理程序属性。
赋值代码运行之后才会给事件处理程序赋值。
所赋函数被视为元素的办法。=> 事件处理程序会在元素的作用域中运行,即 this 等于元素。
let btn = document.querySelector('#myBtn');
btn.onclick = function() {console.log(this.id); // "myBtn"
}
以这种形式增加事件处理程序是 注册在事件流的冒泡阶段 的。
通过将事件处理程序属性的值设置为 null,能够移除通过 DOM0 形式增加的事件处理程序。(在 HTML 中指定的事件处理程序,也能够通过 JavaScript 将相应属性设置为 null 来移除)
btn.onclick = null;
DOM2 事件处理程序
DOM2 Events 为事件处理程序的赋值和移除定义了两个办法:addEventListener()和 removeEventListener()。裸露在所有 DOM 节点上。
接管 3 个参数:事件名、事件处理函数和一个示意是否在捕捉阶段调用处理函数的布尔值(默认值为 false,在冒泡阶段调用)。
这个事件处理程序同样在被附加到的元素的作用域中运行:this 等于元素。
次要劣势 :能够为同一个事件增加多个事件处理程序。多个事件处理程序 以增加程序 来触发。
通过 addEventListener()增加的事件处理程序 只能 应用 removeEventListener()并传入与增加时同样的参数来移除。(事件处理函数必须是同一个)
大多数状况下,事件处理程序会被 增加到事件流的冒泡阶段,次要起因 是跨浏览器兼容性好。(除非须要在事件达到其指定指标之前拦挡事件)
IE 事件处理程序
IE 实现了与 DOM 相似的办法,attachEvent()和 detachEvent()。
接管 2 个参数:事件处理程序的名字 和事件处理函数。因为 IE8 及更早版本只反对事件冒泡,所以应用 attachEvent()增加的事件处理程序会增加到冒泡阶段。
在 IE 中应用 attachEvent()与应用 DOM0 形式的 次要区别 在于事件处理程序的作用域。应用 attachEvent()时,事件处理程序是在全局作用域中运行的,因而 this 等于 window。
attachEvent()办法也能够给一个元素增加多个事件处理程序。以增加它们的程序 反向触发。
应用 attachEvent()增加的事件处理程序将应用 detachEvent()来移除,只有提供雷同的参数(处理函数是雷同的函数援用)。
let btn = document.querySelector('#myBtn');
var handler = function() {console.log("Clicked");
};
btn.attachEvent("onclick", handler);
btn.detachEvent("onclick", handler);
跨浏览器事件处理程序
以跨浏览器兼容的形式处理事件。
本人编写跨浏览器事件处理代码 次要依赖能力检测。要确保最大兼容性,只有让代码在冒泡阶段运行即可。
var EventUtil = {addHandler: function(element, type, handler) {if(element.addEventListener) {element.addEventListener(type, handler, false);
} else if(element.attachEvent) {element.attachEvent("on"+type, handler);
} else { // 默认 DOM0 形式
element["on"+type] = handler;
}
},
removeHandler: function(element, type, handler) {if(element.removeEventListener) {element.removeEventListener(type, handler, false);
} else if(element.detachEvent) {element.detachEvent("on"+type, handler);
} else { // 默认 DOM0 形式
element["on"+type] = null;
}
}
};
// 应用
let btn = document.querySelector('#myBtn');
let handler = function() {console.log("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
EventUtil.removeHandler(btn, "click", handler);
没有解决的存在的问题:
- IE 的作用域问题。(attachEvent()中 this 等于 window)
- 多个事件处理程序执行程序问题。DOM2 以增加程序,IE 为增加程序的反向
- DOM0 只反对给一个事件增加一个处理程序。(DOM0 浏览器曾经很少人应用,问题应该不大)
事件对象 event
在 DOM 中产生事件时,所有相干信息(如事件指标元素、事件类型)都会被收集并存储在一个名为 event 的对象中。
DOM 事件对象
在 DOM 合规的浏览器中,event 对象是传给事件处理程序的惟一参数。不论以哪种形式(DOM0 或 DOM2)指定事件处理程序,都会传入这个 event 对象。在通过 HTML 属性指定的事件处理程序中,同样能够应用变量 event 援用事件对象。
所有事件对象蕴含的公共属性和办法:
- bubbles。布尔值。是否冒泡
- cancelable。布尔值。是否能够勾销事件的默认行为
- currentTarget。元素。以后事件处理程序所在的元素
- defaultPrevented。布尔值。true 示意曾经调用 preventDefault()办法。(DOM3 Events 新增)
- detail。整数(??)。事件相干的其余信息
- eventPhase。整数。示意调用事件处理程序的阶段:1- 捕捉阶段;2- 达到指标;3- 冒泡阶段
- target。元素。事件指标元素
- trusted。布尔值。true 示意事件由浏览器生成;false 示意事件由开发者通过 JavaScript 创立。(DOM3 Events 新增)
- type。字符串。被触发的事件类型
- View。AbstractView。与事件相干的形象视图;等于事件所产生的 window 对象
- preventDefault()。函数。用于勾销事件的默认行为 => cancelable 为 true 时才可调用
- stopImmediatePropagation()。函数。用于勾销所有后续事件捕捉或事件冒泡,并阻止调用任何后续事件处理程序。(DOM3 Events 新增)
- stopPropagation()。函数。用于勾销所有后续事件捕捉或事件冒泡 => bubbles 为 true 时才可调用
在事件处理程序外部,this 始终等于 currentTarget。this === event.currentTarget
。
如果事件处理程序间接增加在用意的指标,则 this、currentTarget 和 target 三者相等。
type 属性在一个处理程序解决多个事件时很有用:依据事件类型,做出不同的响应。
preventDefault()可阻止特定事件的默认动作,如链接的默认行为是被单击时导航到 href 属性指定的 URL。任何可调用 preventDefault()勾销默认行为的事件,其 event 对象的 cancelable 属性都会设置为 true。
stopPropagation()用于立刻阻止事件流在 DOM 构造中流传,勾销后续的事件捕捉或冒泡。
eventPhase 属性可用于确定事件流以后所处的阶段。如果事件处理程序在指标上被调用,则 eventPhase 等于 2 => 尽管”达到指标“是在冒泡阶段产生的,但 eventPhase 等于 2。=> 当 eventPhase 等于 2,this、currentTarget 和 target 三者相等。
event 对象只在事件处理程序执行期间存在,一旦执行结束,就会被销毁。
IE 事件对象
IE 事件对象能够 基于事件处理程序被指定的形式 以不同的形式来拜访。
- 如果应用 DOM0 形式指定,则 event 对象是 window 的一个属性
- 如果应用 attachEvent()指定,则 event 对象会作为惟一的参数传给处理函数。此时 event 对象依然是 window 的属性,出于不便也将其作为参数传入
- 在通过 HTML 属性形式指定的事件处理程序中,同样能够应用变量 event 援用事件对象。
所有 IE 事件对象都会蕴含的公共属性和办法:
- cancelBubble。布尔值。读 / 写。true 示意勾销冒泡(默认 false),与 stopPropagation()办法成果类似
- returnValue。布尔值。读 / 写。false 示意勾销事件默认行为(默认 true),与 preventDefault()成果雷同
- srcElement。元素。事件指标,即 target
- type。字符串。触发的事件类型
事件处理程序的作用域取决于指定它的形式,所以更好的形式是应用事件对象的 srcElement 属性代替 this。(DOM0 形式下,this 等于元素;attachEvent()形式下,this 等于 window)
与 DOM 不同,无奈通过 JavaScript 确定事件是否能够被勾销。
cancelBubble 属性与 stopPropagation()办法用处类似,但 IE8 及更早版本不反对捕捉阶段,所以只会勾销冒泡。
跨浏览器事件对象
DOM 事件对象中蕴含 IE 事件对象的所有信息和能力,只是模式不同。这些共性可让两种事件模型之间的映射成为可能。
var EventUtil = {addHandler: function(element, type, handler) {// ...},
removeHandler: function(element, type, handler) {// ...},
getEvent: function(event) { // IE 事件中以 DOM0 形式指定事件处理程序时,event 对象是 window 的一个属性
return event ? event || window.event;
},
getTarget: function(event) {return event.target || event.srcElement;},
preventDefault: function(event) {if(event.preventDefault) {event.preventDefault();
} else {event.returnValue = false;}
},
stopPropagation: function(event) { // 可能会进行事件冒泡,也可能既会进行事件冒泡也进行事件捕捉
if(event.stopPropagation) {event.stopPropagation();
} else {event.cancelBubble = true;}
}
};
// 应用
let btn = document.querySelector('#myBtn');
btn.onclick = function(event) {event = EventUtil.getEvent(event);
let target = EventUtil.getTarget(event);
EventUtil.preventDefault(event); // 阻止事件的默认行为
EventUtil.stopPropagation(event); // 阻止事件冒泡
};
事件类型
所产生事件的类型决定了事件对象中会保留什么信息。DOM3 Events 定义的事件类型:
- 用户界面事件(UIEvent):与 BOM 交互的通用浏览器事件
- 焦点事件(FocusEvent):元素取得和失去焦点时触发
- 鼠标事件(MouseEvent):鼠标在页面上执行某些操作时触发
- 滚轮事件(WheelEvent):应用鼠标滚轮(或相似设施)时触发
- 输出事件(InputEvent):向文档中输出文本时触发
- 键盘事件(KeyboardEvent):键盘在页面上执行某些操作时触发
- 合成事件(CompositionEvent):应用某种 IME(Input Method Editor,输入法编辑器)输出字符时触发
- HTML5 还定义了另一组事件
- 浏览器通常在 DOM 和 BOM 上实现专有事件:依据开发者需要,不同浏览器的实现可能不同
DOM3 Events 在 DOM2 Events 根底上从新定义了事件,并减少了新的事件类型。所有支流浏览器都反对 DOM2 Events 和 DOM3Events。
用户界面事件 UIEvent
不肯定跟用户操作无关。保留它们是为了向后兼容。次要有以下几种:
- DOMActivate(DOM3 Events 中曾经废除)。元素被用户通过鼠标或键盘操作激活时触发,浏览器实现之间存在差别
- load。window(页面加载实现后触发);窗套 frameset(所有窗格 frame 都加载实现后触发);img(图片加载实现后触发);object(相应对象加载实现后触发)
- unload。window(页面齐全卸载后触发);窗套(所有窗格都卸载实现后触发);object(相应对象卸载实现后触发)
- abort。object(相应对象加载实现前被用户提前终止下载时触发)
- error。window(JavaScript 报错时触发);img(无奈加载指定图片时触发);object(无奈加载相应对象时触发);窗套(一个或多个窗格无奈实现加载时触发)
- select。在文本框(input 或 textarea)上用户抉择了一个或多个字符时触发
- resize。window 或窗格(窗口或窗格被缩放时触发)
- scroll。当用户滚动 蕴含滚动条的元素 时在元素上触发。body 元素蕴含已加载页面的滚动条
大多数 HTML 事件与 window 对象和表单控件无关。除了 DOMActivate,其余在 DOM2 Events 中都被归为 HTML Events。(DOMActivate 是 UI 事件)
焦点事件 FocusEvent
页面元素取得或失去焦点时触发。能够与 document.hasFocus()和 document.activeElement 一起 为开发者提供 用户在页面中导航的信息。焦点事件有以下 6 种:
- blur。失去焦点时触发。不冒泡,所有浏览器都反对
- DOMFocusIn(DOM3 Events 中曾经废除,举荐 focusin)。取得焦点时触发。focus 的冒泡版。Opera 惟一反对
- DOMFocusOut(DOM3 Events 中曾经废除,举荐 focusout)。失去焦点时触发,blur 的通用版。Opera 惟一反对
- focus。取得焦点时触发。不冒泡,所有浏览器都反对
- focusin。取得焦点时触发。focus 的冒泡版
- focusout。失去焦点时触发。blur 的通用版
两个次要事件是 focus 和 blur,它们最大的问题是不冒泡。
当焦点从页面中的一个元素 A 移到另一个元素 B 上,会顺次产生如下事件(测试,与书中不统一):
1)A:blur
2)A:focusout
3)B:focus
4)B:focusin
DOMFocusOut 和 DOMFocusIn 未验证
鼠标和滚轮事件 MouseEvent
鼠标是用户的次要定位设施。DOM3 Events 定义了 9 种鼠标事件:
- click。用户单击鼠标主键(通常是左键)或按键盘回车键时触发。
- dblclick。用户双击鼠标主键(通常是左键)时触发(DOM3 Events 中标准化)
- mousedown。用户按下任意鼠标键时触发。不能通过键盘触发
- mouseenter。用户把鼠标光标从元素内部移到元素外部时触发。不冒泡,也不会在光标通过后辈元素时触发。(DOM3 Events 中新增)
- mouseleave。用户把鼠标光标从元素外部移到元素内部时触发。不冒泡,也不会在光标通过后辈元素时触发。(DOM3 Events 中新增)
- mousemove。鼠标光标在元素上挪动时重复触发。不能通过键盘触发
- mouseout。用户把鼠标光标从一个元素移到另一个元素上(内部元素或子元素)时触发。不能通过键盘触发
- mouseover。用户把鼠标光标从元素内部移到元素外部时触发。不能通过键盘触发
- mouseup。用户开释鼠标键时触发。不能通过键盘触发
页面中所有元素都反对鼠标事件。除了 mouseenter 和 mouseleave,其余鼠标事件都会冒泡,都能够被勾销,这会影响浏览器的默认行为。因为事件之间存在关系,因而勾销鼠标事件的默认行为也会影响其余事件。
双击鼠标主键会按如下程序触发事件:
1)mousedown
2)mouseup
3)click
4)mousedown
5)mouseup
6)click
7)dblclick
click 和 dblclick 在触发前都依赖其余事件触发,mousedown 和 mouseup 则不会受其余事件影响。
IE8 和更早的版本的实现中存在问题,会导致双击事件跳过第二次 mousedown 和 click 事件。
1)mousedown
2)mouseup
3)click
4)mouseup
5)dblclick
DOM3 Events 中鼠标事件对应的类型是”MouseEvent“(复数模式)
鼠标事件还有一个名为滚轮事件的子类别。滚轮事件只有一个事件 mousewheel,对应鼠标滚轮或带滚轮的相似设施上滚轮的交互。
鼠标事件 event 对象的一些属性:
-
客户端坐标
注:客户端坐标不思考页面滚动
-
页面坐标
在页面上的地位。示意事件产生时鼠标光标在页面上的坐标,通过 event 对象的 pageX 和 pageY 属性获取。
反映的是光标到页面而非视口右边与上边的间隔。
-
屏幕坐标
鼠标光标在屏幕上的坐标,通过 event 对象的 screenX 和 screenY 属性获取。
-
润饰键
有时要确定用户想实现的操作,还要 思考键盘按键的状态。
键盘上的润饰键 Shift、Ctrl、Alt 和 Meta(win 的 window 键,mac 的 command 键)常常用于批改鼠标事件的行为。
4 个属性来示意这几个润饰键的状态:shiftKey、ctrlKey、altKey、metaKey。(被按下为 true,否则为 false)
当初浏览器反对所有 4 个润饰键,IE8 及更早版本不反对 metaKey 属性。
-
相干元素
对 mouseover 和 mouseout 事件而言,还存在 与事件相干的其余元素。
-
鼠标按键
对 mousedown 和 mouseup 事件来说,event 对象上会有一个 button 属性,示意按下或开释的是哪个按键。DOM 为 button 属性定义了 3 个值:0- 主键;1- 中键(通常是滚轮键);2- 副键。
IE8 及更早版本也提供了 button 属性,思考了同时按多个键的状况。
-
额定事件信息
DOM2 Events 标准在 event 对象上提供了detail 属性,以给出对于事件的更多信息。对鼠标事件来说,detail 蕴含一个数值,示意在给定地位上产生了多少次单击(间断单击)。每次单击会加 1。间断点击中断会重置为 0。
IE 还为每个鼠标事件提供了以下额定信息:
- altLeft,布尔值,是否按下了左 Alt 键(如果为 true,则 altKey 也为 true)
- ctrlLeft,布尔值,是否按下左 Ctrl 键(如果为 true,则 ctrlKey 也为 true)
- offsetX,光标绝对于指标元素边界的 x 坐标
- offsetY,光标绝对于指标元素边界的 y 坐标
- shiftLeft,布尔值,是否按下了左 Shift 键(如果为 true,则 shiftKey 也为 true)
滚轮 mousewheel 事件
在用户应用鼠标滚轮时触发,包含在垂直方向上任意滚动。会在任何元素上触发,并(在 IE8 中)冒泡到 document 和(所有古代浏览器中)window。
event 对象蕴含鼠标事件的所有规范信息,此外还有一个名为 wheelDelta 的属性。
少数状况下只需晓得滚轮滚动的方向,而这通过 wheelDelta 值的符号就能够晓得。(向前滚动一次 +120,向后滚动一次 -120)
触摸屏设施
触摸屏通常不反对鼠标操作。
- 不反对 dblclick 事件。(测试一加三能够)
- 单指导触屏幕上的可点击元素会触发 mousemove 事件。(测试一加三不行)可点击元素是指导击时有默认动作的元素(如链接)或指定了 onclick 事件处理程序的元素
- mousemove 事件也会触发 mouseover 和 mouseout 事件。(还未测试)
- 双指导触屏幕并滑动导致页面滚动时会触发 mousewheel 和 scroll 事件。(还未测试)
无障碍问题
如果 Web 利用或网站要思考残障人士,特地是应用屏幕阅读器的用户,那么必须小心应用鼠标事件(除了回车键能够触发 click 事件,其余鼠标事件不能通过键盘触发)。倡议不要应用 click 事件之外的其余鼠标事件向用户提醒性能或触发代码执行。=> 会严格障碍盲人或视障用户应用。
几条 应用鼠标事件时应该遵循的无障碍倡议:
- 应用 click 事件执行代码。当应用 onmousedown 执行代码时,应用程序会运行得更快,但屏幕阅读器无奈触发 mousedown 事件
- 不要应用 mouseover 向用户显示新选项。无奈触发。能够思考键盘快捷键
- 不要应用 dblclick 执行重要的操作。无奈触发
更多网站无障碍的信息,能够参考 WebAIM 网站。
键盘与输出事件 KeyboardEvent
用户操作键盘时触发。很大水平上是基于原始的 DOM0 实现的。
DOM3 Events 为键盘事件提供了一个首先在 IE9 中齐全实现的标准,其余浏览器也开始实现该标准,但仍存在很多遗留的实现。
蕴含 3 个事件:
- keydown,按下键盘上某个键时触发,继续按钮会反复触发
- keypress(DOM3 Events 曾经废除,举荐 textInput 事件),按下键盘上某个键并产生字符时触发,继续按住会反复触发。Esc 键也会触发(Chrome 里测试不会触发?)。
- keyup,用户开释键盘上某个键时触发。
所有元素都反对这些事件。但在文本框中输出内容时最容易看到。
输出事件只有一个:textInput。是对 keypress 事件的扩大,用于在文本显示给用户之前更不便地截获文本输出。会在文本被插入到文本框之前触发。
- 当用户按下某个字符键时,会触发 keydown 事件,而后触发 keypress 事件,最初触发 keyup 事件。(keydown 和 keypress 会在文本框呈现变动之前触发,keyup 会在文本框呈现变动之后触发);如果按住不放,keydown 和 keypress 会反复触发,直到这个键被开释。
- 当用户按下非字符键时,会触发 keydown 事件,而后触发 keyup 事件。如果按住不放,keydown 会反复触发,直到这个键被开释。
注:键盘事件反对与鼠标事件雷同的润饰键。
键盘事件 event 对象的一些属性:
-
键码 keyCode
keydown 和 keyup 事件,event 对象的 keyCode 属性会保留一个键码。
对于字母和数字键,keyCode 的值与大写字母和数字的 ASCII 编码统一。与是否按了 Shift 键无关。
DOM 和 IE 的 event 对象都反对 keyCode 属性
-
字符编码 charCode
keypress 事件,意味着按键会影响屏幕上显示的文本。对插入或移除字符的键,所有浏览器都会触发 keypress 事件,其余键则取决于浏览器。
event 对象上的 charCode 属性,只有产生 keypress 事件时这个属性才会被设置值(此时与 keyCode 属性相等)。蕴含的是按键字符对应的 ASCII 编码。
IE8 及更早版本和 Opera 应用 keyCode 传播字符的 ASCII 编码。要以跨浏览器形式获取字符编码,首先要检测 charCode 属性是否有值,如果没有再应用 keyCode。
有了字母编码,就能够应用 String.fromCharCode()办法将其转换为理论的字符了。
DOM3 的变动
DOM3 Events 标准并未规定 charCode 属性,而是 定义了 key 和 char 两个新属性。
key 属性用于代替 keyCode,且蕴含字符串。按下字符键时,key 等于文本字符;按下非字符键时,key 的值是键名(如”Shift“或”ArrowDown“)
char 属性在按下字符键时与 key 相似,在按下非字符键时为 null。(测试 Chrome 中 keypress 和 keydown 的 event 对象此属性都无)
IE 反对 key 属性但不反对 char 属性。
Safari 和 Chrome 反对 keyIdentifier 属性(测试 Chrome 无此属性)。对于字符键,keyIdentifier 返回以”U+0000“模式示意 Unicode 值的字符串模式的字符编码。
因为 不足跨浏览器反对,不倡议应用 key、keyIdentifier 和 char。
DOM3 Events 也反对 一个名为 location 的属性,是一个数值,示意是在哪里按的键。可能的值为:0- 默认键;1- 右边;2- 左边;3- 数字键盘;4- 挪动设施(虚构键盘);5- 游戏手柄。Safari 和 Chrome 反对一个等价的 keyLocation 属性(实现有问题)
没有失去广泛支持,不倡议在跨浏览器开发时应用 location 属性。
给 event 对象 减少了 getModifierState()办法,接管一个参数,一个等于 Shift、Control、Alt、AltGraph 或 Meta 的字符串,示意要检测的润饰键。如果给定 的润饰键被按钮,则返回 true。(也可间接应用 event 对象的 shiftKey、ctrlKey、altKey 或 metaKey 属性获取)
输出 textInput 事件
DOM3 Events 标准新增,在字符被输出到可编辑区域时触发。
与 keypress 比对:1. keypress 会在任何能够取得焦点的元素上触发,textInput 只在可编辑区域上触发;2. textInput 只在有新字符被插入时才会触发,而 keypress 对任何可能影响文本的键都会触发(包含退格键(Chrome 里测试不会触发?))。3. 应用输入法(搜狗)时,在触发合成事件时不会触发 keypress,在 compositionend 触发之前会先触发 textInput 事件。4. 应用键盘输入先触发 keypress,再触发 textInput。
该事件次要关注字符,event 对象上有 data 属性,为被插入的字符(非字符编码);还有一个 inputMethod 的属性(Chrome 中测试无此属性打印为 undefined),示意向控件中输出文本的伎俩,能够辅助验证
设施上的键盘事件(非键盘)
任天堂 Wii
合成事件
DOM3 Events 中新增,用于解决通常应用 IME 输出时的简单输出序列。IME 能够让用户输出物理键盘上没有的字符,通常须要按下多个键能力输出一个字符,合成事件用于检测和管制这种输出。
合成事件有以下 3 种:
- compositionstart,示意输出行将开始
- compositionupdate,在新字符插入输出字段时触发;
- compositionend,示意恢复正常键盘输入
惟一减少的事件属性是 data:
- 在 compositionstart 中,为正在编辑的文本(默认是空串,或者是选中的文本)
- 在 compositionupdate 中,为要插入的新字符
- 在 compositionend 中,为本次合成过程中输出的全部内容
测试失去的触发程序:
keydown -> …start -> …update -> ((keyup) -> keydown -> …update -> (keyup))(循环触发) -> …update(此时 data 与 …end 事件中的 data 统一) -> textInput -> …end -> keyup
变动事件
DOM2 的变动事件(Mutation Events),在 DOM 发生变化时提供告诉。
(已废除)
曾经被 Mutation Observers 所取代(第 14 章)
HTML5 事件
HTML5 中失去浏览器较好反对的一些事件(标准未涵盖)
-
contextmenu 事件
单击鼠标右键(Ctrl+ 单击左键)。用于 容许开发者勾销默认的上下文菜单并提供自定义菜单。冒泡。
事件指标是触发操作的元素,这个事件在所有浏览器中都能够勾销(event.preventDefault()或 event.returnValue 设置为 false)。
通常通过 onclick 事件处理程序触发暗藏(自定义菜单)。
-
beforeunload 事件
在 window 上触发。用于 给开发者提供阻止页面被卸载的机会。在页面行将从浏览器中卸载时触发。
不能取消,否则就意味着能够把用户永恒拦截在一个页面上。
该事件会向用户显示一个确认框。用户能够点击勾销或者确认来到页面。须要将 event.returnValue 设置为要在确认框中显示的字符串(对于 IE 和 FF 来说)(测试 FF 显示的提醒文字与 returnValue 属性值无关),并将其作为函数值返回(对于 Safari 和 Chrome 来说)(测试 Chrome 无返回值也无影响)
-
DOMContentLoaded 事件
会在 DOM 树构建实现后立刻触发,而不必期待图片、JavaScript 文件、CSS 文件或其余资源加载实现。(能够在内部资源下载的同时指定事件处理程序,从而让用户可能更快地与页面交互)
比对 load 事件:要期待很多内部资源加载实现。
须要给 document 或 window 增加事件处理程序(理论的事件指标是 document,会冒泡到 window)。
通常 用于增加事件处理程序或执行其余 DOM 操作。这个事件始终在 load 事件之前触发。
对于不反对 DOMContentLoaded 事件的浏览器,能够应用超时为 0 的 setTimeout()函数,通过其回调来设置事件处理程序。实质上是在以后 JavaScript 过程执行结束后立刻执行这个回调。(与 DOMContentLoaded 触发机会统一无绝对把握,最好是页面上的第一个超时代码)
-
readystatechange 事件
IE 首先定义。用于 提供文档或元素加载状态的信息,但行为有时不稳固。
event.target 或其余反对 readystatechange 事件的对象都有一个 readyState 属性,该属性可能为以下 5 个值:
- uninitialized:对象存在并尚未初始化
- loading:对象正在加载数据
- loaded:对象曾经加载完数据
- interactive √:对象能够交互,但尚未加载实现
- complete √:对象加载实现
并非所有对象都会经验所有 readyState 阶段(Chrome 测试 document 只经验了两个阶段:interactive 和 complete)
值为”interactive“的 readyState 阶段,机会相似于 DOMContentLoaded。进入交互阶段,意味着 DOM 树已加载实现。(此时图片和其余内部资源不肯定都加载实现了)。
与 load 事件独特应用时,这个事件的触发程序不能保障。interactive 和 complete 的程序也不是固定的,为了抢到较早的机会,须要同时检测交互阶段和实现阶段(能够保障尽可能靠近应用 DOMContentLoaded 事件的成果)。
-
pageshow 与 pagehide 事件
FF 和 Opera 开发的一个名为往返缓存(bfcache,back-forward cache)的性能,旨在 应用浏览器”后退“和”后退“按钮时放慢页面之间的切换。不仅存储页面数据,也存储 DOM 和 JavaScript 状态,实际上是把整个页面都保留在内存里。
如果页面在缓存中,导航到这个页面时就不会触发 load 事件。
- pageshow:在页面显示时触发,无论是否来自往返缓存。新加载的页面,会在 load 事件之后触发;来自往返缓存的页面,会在页面状态完全恢复后触发。事件指标是 document,但事件处理程序必须增加到 window 上。(点击了浏览器的”刷新“按钮,页面会从新加载)。event 对象中的 persisted 属性为布尔值,示意页面内容是否来自往返缓存。
-
pagehide:在页面从浏览器中卸载后,在 unload 事件之前触发。事件指标是 document,但事件处理程序必须增加到 window 上。event 对象中的 persisted 属性为布尔值,示意页面在卸载后是否保留在往返缓存中。
注册了 onunload 事件处理程序的页面会主动排除在往返缓存之外(测试 beforeunload 也会影响),因为 onunload 的典型场景就是撤销 onload 事件产生时所做的事件,如果应用往返缓存,下一次页面显示时就不会触发 onload 事件,这可能导致页面无奈应用。
-
hashchange 事件
用于在 URL 散列值(# 前面的局部)发生变化时告诉开发者。
事件处理程序必须增加给 window。event 对象有两个新属性:oldURL 和 newURL,别离保留变动前后的 URL,蕴含散列值的残缺 URL。如果想确定以后的散列值,最好应用 location 对象。
设施事件
智能手机和平板计算机 => 交互的新形式
用于确定用户应用设施的形式。
-
orientationchange 事件
苹果,挪动 Safari 浏览器。判断用户的设施是处于垂直模式还是程度模式。window.orientation 属性,有 3 种值:0- 垂直模式,90- 左转程度模式(Home 键在右),-90- 右转程度模式(Home 键在左)。当属性值扭转就会触发该事件。
所有 iOS 设施都反对该事件和该属性。(测试锁定竖屏 => 不会扭转)
被认为是 window 事件,也可给 body 元素增加 onorientationchange 属性来指定事件处理程序。
-
deviceorientation 事件
DeviceOrientationEvent 标准定义的事件。
如果能够获取设施的减速计信息,且数据产生了变动,就会在 window 上触发。只反馈设施在空间中的朝向,与挪动无关。
设施自身处于 3D 空间,x 轴方向为从设施左侧到右侧,y 轴方向为从设施底部到上部,z 轴方向为从设施反面到侧面。
event 对象蕴含各个轴绝对于设施静置时坐标值的变动,次要有 5 个属性:
- alpha:0~360 内的浮点值,示意 围绕 z 轴旋转 时 y 轴的度数(左右转)
- beta:-180~180 内的浮点值,示意 围绕 x 轴旋转 时 z 轴的度数(前后转)
- gamma:-90~90 内的浮点值,示意 围绕 y 轴旋转 时 z 轴的度数(扭转)。
- absolute:布尔值,示意设施是否返回绝对值。
- compassCalibrated:布尔值,示意设施的指南针是否正确校准。
测试 iPhone8(iOS11.4.1)平放在桌面上也始终监听到变动(?),测试 Android(一加三)平放在桌面上后不会变动
-
devicemotion 事件
DeviceOrientationEvent 标准定义的事件。
用于提醒设施实际上在挪动,而不仅仅是扭转了朝向。event 对象蕴含的额定属性:
- acceleration:对象,蕴含 x、y 和 z 属性,反映不思考重力状况下各个维度的减速信息
- accelerationIncludingGravity:对象,蕴含 x、y 和 z 属性,反映各个维度的减速信息,蕴含 z 轴天然重力加速度
- interval:毫秒,间隔下次触发事件的工夫。此值在事件之间应为常量。
- rotationRate:对象,蕴含 alpha、beta 和 gamma 属性,示意设施朝向。
如果无奈提供 acceleration、accelerationIncludingGravity、rotationRate 信息,则属性值为 null。=> 应用之前必须先检测
测试 iPhone8(iOS11.4.1)平放在桌面上也始终监听到变动,测试 Android(一加三)平放在桌面上也始终监听到变动
触摸及手势事件
只实用于触屏设施。
Webkit 为 Android 定制了很多专有事件,成为了事实标准,并被纳入 W3C 的 Touch Events 标准。
-
触摸事件
如下几种:
- touchstart:手指放到屏幕上时触发
- touchmove:手指在屏幕上滑动时间断触发。在此事件中调用 preventDefault()能够阻止滚动(测试并不能)
- touchend:手指从屏幕上移开时触发
- touchcancel:零碎进行跟踪触摸时触发。文档未明确什么状况下进行跟踪。
都会冒泡,都能够被勾销。不属于 DOM 标准,浏览器以兼容 DOM 的形式实现它们。每个触摸事件的 event 对象都提供了鼠标事件的公共属性,另外提供以下 3 个属性用于跟踪触点:
- touches:Touch 对象的数组,示意以后屏幕上的每个触点。
- targetTouches:Touch 对象的数组,示意特定于事件指标的触点。
- changedTouches:Touch 对象的数组,示意自上次用户动作之后变动的触点
每个 Touch 对象蕴含一些属性,可用于追踪屏幕上的触摸轨迹。(针对一个触点)touchend 事件触发时 touches 汇合中什么也没有,这是因为没有滚动的触点了。
当手指点触屏幕上的元素时,顺次触发的事件(测试与书本不统一):
1)touchstart
2)touchend
3)mousemove
4)mousedown
5)mouseup
6)click
-
手势事件
iOS2.0 中的 Safari 中减少。在两个手指触碰屏幕且绝对间隔或旋转角度变动时触发。有如下 3 种:
- gesturestart:一个手指在屏幕上,再把另一手指放到屏幕上时触发
- gesturechange:任何一个手指在屏幕上的地位发生变化时触发
- gestureend:其中一个手指来到屏幕时触发
都会冒泡。
只有在两个手指同时接触事件接收者时(指标元素边界以内),这些事件才会触发。
触摸事件和手势事件存在肯定的关系。
每个手势事件的 event 对象都蕴含所有规范的鼠标事件属性,新增了两个属性是 rotation 和 scale。
rotation:示意手指变动旋转的度数,负值示意逆时针旋转,正值示意顺时针旋转(从 0 开始);
scale:示意两指之间间隔变动(对捏)的水平,开始时为 1,而后随着间隔增大或放大相应地增大或放大。
触摸事件也会返回 rotation 和 scale 属性,但只在两个手指触碰屏幕时才会变动。
其余一些标准中定义的浏览器事件
参考书本
内存与性能
在 JavaScript 中,页面中事件处理程序的数量与页面整体性能间接相干。
首先,每个函数都是对象,都占用内存空间;其次,为指定事件处理程序所需拜访 DOM 的次数会 先期 造成整个页面交互的提早。
改善页面性能?
事件委托
”过多事件处理程序“的解决方案是应用事件委托。
利用事件冒泡,能够只应用一个事件处理程序来治理一种类型的事件。只有给所有元素(须要解决某种事件的元素)独特的先人节点增加一个事件处理程序,就能够解决问题(依据 target 判断进行不同的解决)。=> 只拜访了一个 DOM 元素和增加了一个事件处理程序。=> 占用内存更少,所有应用按钮的事件(大多数鼠标事件和键盘事件)都实用于这个解决方案。
只有可行,就应该思考只给 document 增加一个事件处理程序,通过它解决页面中所有某种类型的事件。长处如下:
- document 对象随时可用。=> 只有页面渲染出可点击的元素,就能够无提早地起作用。
- 既能够节俭 DOM 援用,也能够节省时间(设置页面事件处理程序的事件)。
- 缩小整个页面所需的内存,晋升整体性能。
最适宜应用事件委托的事件包含:click、mousedown、mouseup、keydown 和 keypress。
删除事件处理程序
把事件处理程序指定给元素后,在浏览器代码和负责页面交互的 JavaScript 代码之间就建设了分割。这种分割建设得越多,页面性能就越差。除了应用事件委托缩小这种分割外,还应及时删除不必的事件处理程序。
很多 Web 利用性能不佳都是因为 无用的事件处理程序长驻内存 导致的。起因如下:
-
删除带有事件处理程序的元素。如应用办法 removeChild()或 replaceChild()删除节点,或应用 innerHTML 整体替换页面的某一部分。=> 被删除的元素上若有事件处理程序,就不会被垃圾收集程序失常清理。(特地是 IE8 及更早版本,元素的援用和事件处理程序的援用)
如果晓得某个元素会被删除,那么最好在 删除它之前 手工删除它的事件处理程序(或者不间接给它增加事件处理程序,应用事件委托)。=> 确保内存被回收,元素也能够平安地从 DOM 中删掉。
留神:在事件处理程序中删除元素会阻止事件冒泡。只有事件指标依然存在于文档中时,事件才会冒泡。
-
页面卸载导致内存中残留援用。事件处理程序没有被清理,会残留在内存中。
最好在 onunload 事件处理程序中趁页面尚未卸载先删除所有事件处理程序。=> 应用事件委托的劣势:事件处理程序很少。
模仿事件
通常事件都是由用户交互或浏览器性能触发。
能够通过 JavaScript 在任何时候触发任意事件 => 在测试 Web 利用时特地有用
DOM3 标准指明了模仿特定类型事件的形式。
DOM 事件模仿
步骤:
-
应用 document.createEvent()办法创立一个 event 对象。
createEvent()办法接管一个参数,一个示意要创立事件类型的字符串。DOM2 是英文复数模式,DOM3 中是英文复数模式。可用值为以下之一:
- ”UIEvents“(DOM3 是”UIEvent“):通用用户界面事件(鼠标事件和键盘事件都继承于此)
- ”MouseEvents“(DOM3 是”MouseEvent“):通用鼠标事件
- ”HTMLEvents“(DOM3 中无):通用 HTML 事件(已扩散到其余事件大类中)
- 键盘事件(DOM3 Events 中减少)
- “Events”:通用事件
- “CustomEvent”(DOM3 中减少):自定义事件
-
应用事件相干的信息来初始化
每种类型的 event 对象都有特定的办法,取决于调用 createEvent()时传入的参数
-
触发事件
事件指标调用 dispatchEvent()办法。该办法存在于所有反对事件的 DOM 节点上。
接管一个参数,即要触发事件的 event 对象
- 冒泡并触发事件处理程序执行
不同事件类型的模仿:
-
鼠标事件
- 调用 createEvent()并传入”MouseEvents“参数
- 调用返回的 event 对象的 initMouseEvent()办法,为新对象指定鼠标的特定信息。接管 15 个参数,别离对应鼠标事件会裸露的属性,如 type、bubbles、cancelable、view 等,这四个是正确模仿事件惟一重要的几个参数,因为浏览器要用到,其余参数则是事件处理程序要用的。
- event 对象的 target 属性会主动设置为调用 dispatchEvent()办法的节点
所有鼠标事件都能够在 DOM 合规的浏览器中模仿进去
-
键盘事件
- DOM3 中创立键盘事件的形式是给 createEvent()办法传入参数”KeyboardEvent“
- 调用返回的 event 对象的 initKeyboardEvent()办法。接管 8 个参数,包含 type、bubbles、cancelable、view 等。
DOM3 Events 中废除了 keypress 事件,因而只能通过上述形式模仿 keydown 和 keyup 事件。
在应用
document.createEvent("KeyboardEvent")
之前,最好检测一下浏览器对 DOM3 键盘事件的反对状况document.implementation.hasFeature("KeyboardEvents", "3.0")
。测试 Chrome,调用 initKeyboardEvent()办法传入的 key 和 modifier 参数与在事件处理程序中打印进去的属性不统一,能够应用
new KeyboardEvent()
(参数与在事件处理程序中打印出的统一),另,两种模仿都不会使文本框中有内容FF 限定:
- 给 createEvent()传入”KeyEvents“来创立键盘事件
- 调用 event 对象的 initKeyEvent()办法。接管 10 个参数,包含 type、bubbles、cancelable、view 等。
测试:ff(88.0)显示不反对 Uncaught DOMException: Operation is not supported
其余不反对键盘事件的浏览器:
- 创立一个通用的事件,给 createEvent()办法传入参数”Events“
- 调用 event 对象的 initEvent()办法
- 通过 event.xxx 形式指定特定于键盘的信息
必须应用通用事件而不是用户界面事件,因为用户界面事件不容许间接给 event 对象增加属性
-
其余事件
HTML 事件:
- 调用 createEvent()办法并传入“HTMLEvents”
- 调用返回的 event 对象的 initEvent()办法来初始化信息
测试:模仿 focus,能监听到事件,然而没有光标
-
自定义 DOM 事件
DOM3 新增自定义事件类型。不触发原生 DOM 事件。
- 调用 createEvent()并传入参数“CustomEvent”
- 调用返回的 event 对象的 initCustomEvent()办法,接管 4 个参数:type、bubbles、cancelable、detail
- 调用 dispatchEvent()
IE 事件模仿
在 IE8 及更早版本中模仿事件。
步骤:
- 应用 document 对象的 createEventObject()办法来创立 event 对象。不接管参数,返回一个通用 event 对象
- 手工给返回的对象指定心愿该对象具备的所有属性。(无初始化办法)可指定任何属性,包含 IE8 及更早版本不反对的属性。这些属性值对于事件来说并不重要,只有事件处理程序才会应用它们。
- 在事件指标上调用 fireEvent()办法。接管 2 个参数:事件处理程序的名字和 event 对象。srcElement 和 type 属性会主动指派到 event 对象。
IE 反对的所有事件都能够通过雷同的形式来模仿。
小结
最常见的事件是在 DOM3 Events 标准或 HTML5 中定义的。
须要思考内存与性能问题:
-
限度页面中事件处理程序数量。=> 防止占用过多内存导致页面响应慢,清理起来更不便
- 应用事件委托
- 在页面卸载或元素从页面删除前,清理掉相干的事件处理程序