Comments (2)
事件类型
Web 浏览器中可能发生的事件有很多类型,不同类型的事件具有不同信息,DOM 3 级事件规定了以下几类事件:
- UI(User Interface,用户界面) 事件
- 焦点事件
- 鼠标事件
- 滚轮事件
- 文本事件
- 键盘事件
- 合成事件
- 变动(mutation)事件
- ……
如何封装一个自定义事件???自定义事件有事件流的概念吗?另外,其实在当前混合式开发过程中,容器也会提供一些事件?事件 vs 生命周期?
UI 事件
现有 UI 事件如下:
- DOMActivate 事件(已废弃):表示元素已经被用户操作(键盘/鼠标)激活
- load 事件:
- 当页面完全加载后在 window 上面触发
- 当所有框架都加载完毕后在框架集上面触发
- 当图像加载完毕后在 img 元素上面触发
- 当嵌入的内容加载完毕后在 object 元素上面触发
- unload 事件:
- 当页面完全卸载后在 window 上面触发(只要用户从一个页面切换到另一个页面,就会发生 unload 事件)。利用这个事件最多的情况是清除引用,以避免内存泄露
- 当所有框架都卸载完毕后在框架集上面触发
- 当图像卸载完毕后在 img 元素上面触发
- 当嵌入的内容卸载完毕后在 object 元素上面触发
- abort 事件:在用户停止下载过程中,如果嵌入的内容没有加载完,则在 object 元素上面触发
- error 事件:
- 当发生 JavaScript 错误时在 window 上面触发
- 当无法加载图像时在 img 元素上面触发
- 当无法加载嵌入内容时在 object 元素上面触发
- 当有一或多个框架无法加载时在框架集上面触发
- select 事件:当用户选择文本框(input/textarea)中的一或多个字符时触发
- resize 事件:当窗口或框架的大小变化时在 window 或框架上面触发
- scroll 事件:当用户滚动带滚动条的元素中的内容时,在该元素上面触发。body 元素中包含所加载页面的滚动条
焦点事件
- blur 事件:在元素失去焦点时触发,这个事件不会冒泡
- DOMFocusIn 事件
- DOMFocusOut 事件
- focus 事件
- focusin 事件
- focusout 事件
当焦点从一个元素(A)移动到另一个元素(B),会依次触发下列事件:
- focusout - A
- focusin - B
- blur - A
- DOMFocusOut - A
- focus - B
- DOMFocusIn - B
鼠标和滚轮事件
- click 事件
- dbclick 事件
- mousedown 事件
- mouseenter 事件
- mouseleave 事件
- mousemove 事件
- mouseout 事件
- mouseover 事件
- mouseup 事件
mousedown、mouseup、click、dbclick触发顺序:
-
mousedown 事件
-
mouseup 事件
-
click 事件
-
mousedown 事件
-
mouseup 事件
-
click 事件
-
dbclick 事件
-
客户区坐标位置:clientX 和 clientY
-
页面坐标位置:pageX 和 pageY
-
屏幕坐标位置:screenX 和 screenY
-
修改键:Shift、Ctrl、Alt、Meta(Windows/Cmd) => shiftKey、ctrlKey、altKey、metaKey
-
相关元素:relatedTarget
-
鼠标按钮:button
触摸设备
无障碍访问
键盘与文本事件
-
keydown 事件
-
keypress 事件
-
keyup 事件
-
键码:keyCode
-
字符编码:charCode
-
textInput事件
复合事件
变动事件
HTML 5 事件
- contextmenu 事件
- beforeunload 事件:之所以有发生在 window 对象上的 beforeunload 事件,是为了让开发人员有可能在页面卸载前阻止这一操作。这个事件会在浏览器卸载页面之前触发,可以通过它来取消卸载并继续使用原有页面。但是,不能彻底取消这个事件,因为那就相当于让用户无法离开当前页面了。为此,这个事件的意图是将控制权交给用户(弹出对话框)。
EventUtil.addHandler(window, "beforeunload", function(event){
event = EventUtil.getEvent(event);
var message = "I'm really going to miss you if you go.";
event.returnValue = message;
return message;
});
- DOMContentLoaded 事件
window 的 load 事件会在页面中的一切都加载完毕时触发,但这个过程可能会因为要加载的外部资源过多而破费周折。DOMContentLoaded 事件则在形成完整的 DOM 树之后就会触发,不理会图像、JavaScript 文件、CSS 文件或其他资源是否已经加载完毕。
要处理 DOMContentLoaded 事件,可以为 document 或 window 添加相应的事件处理程序(尽管这个事件会冒泡到 window ,但它的目标实际上是 document)
EventUtil.addHandler(document, "DOMContentLoaded", function(event){
alert("Content loaded");
});
通常 DOMContentLoaded 事件既可以添加事件处理程序,也可以执行其他 DOM 操作。这个事件始终都会在 load 事件之前触发。
对于不支持 DOMContentLoaded 事件的浏览器,建议在页面加载期间设置一个时间为 0毫秒
的超时调用:
setTimeout(function(){
// attach event handlers here
// 在此添加事件处理程序
}, 0);
=> “在当前 JavaScript 处理完成后立即运行这个函数”,在页面下载和构建期间,只有一个 JavaScript 处理过程,因此超时调用会在该过程结束时立即触发。至于能否与 DOMContentLoaded 被触发的时间能否同步,主要还是取决于用户使用的浏览器和页面中的其他代码。为了确保有效,必须将其作为页面中的第一个超时调用,但也还是无法保证在所有环境中该超时调用一定会早于 load 事件被触发。
-
readystatechange 事件(注意兼容性与差异):readyState 属性
- uninitialize(未初始化):对象存在但尚未初始化
- loading(正在加载):对象正在加载数据
- loaded(加载完毕):对象加载数据完成
- interactive(交互):可以操作对象了,但还没有完全加载
- compete(完成):对象已经加载完毕
-
pageshow 和 pagehide 事件
-
hashchange 事件
HTML 5 新增了此事件,以便在 URL 的参数列表(及 URL 中“#”号后面的所有字符串)发生变化时通知开发人员。必须要把 hashchange 事件处理程序添加给 window 对象,然后 URL 参数列表只要变化就会调用。对应的事件对象额外包含两个属性:oldURL 和 newURL,分别保存着参数列表变化前后的完整 URL。
EventUtil.addHandler(window, "hashchange", function(event){
alert("Current hash: " + location.hash);
});
var isSupported = ("onhashchange" in window); // 可能在 IE 下还有 bug
var isSupported = ("onhashchange" in window) && (document.documentMode === undefined || document.documentMode > 7);
设备事件
- orientationchange 事件
- MozOrientation 事件(Firefox)
- deviceorientation 事件
- devicemotion 事件
触摸与手势事件
- 触摸事件
- touchstart 事件:当手指触摸屏幕时触发,即使已经有一个手指放在了屏幕上也会触发
- touchmove 事件:当手指在屏幕上滑动时连续地触发,在这个事件发生期间,调用 preventDefault() 可以组织滚动
- touchend 事件: 当手指从屏幕上移开时触发
- touchcancel 事件:当系统停止跟踪触摸时触发。(?关于此事件的确切触发时间,文档中没有明确说明)
上述事件都会冒泡,也都可以取消。虽然没在 DOM 规范中定义,但是是以兼容 DOM 的方式实现的 => 每个触摸事件都提供了在鼠标事件中常见属性:bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、ctrlKey 和 metaKey。
除了常见的 DOM 属性外,触摸事件还包含下列三个用于跟踪触摸的属性:
- touches:表示当前跟踪的触摸操作的 Touch 对象的数组
- targetTouches:特定于事件目标的 Touch 对象的数组
- changeTouches:表示自上次触摸以来发生了什么改变的 Touch 对象的数组
每个 Touch 对象包含下列属性:clientX、clientY、identifier、pageX、pageY、screenX、screenY、target
function handleTouchEvent(event){
//only for one touch
if (event.touches.length == 1){
var output = document.getElementById("output");
switch(event.type){
case "touchstart":
output.innerHTML = "Touch started (" + event.touches[0].clientX + "," + event.touches[0].clientY + ")";
break;
case "touchend":
output.innerHTML += "<br>Touch ended (" + event.changedTouches[0].clientX + "," + event.changedTouches[0].clientY + ")";
break;
case "touchmove":
event.preventDefault(); //prevent scrolling
output.innerHTML += "<br>Touch moved (" + event.changedTouches[0].clientX + "," + event.changedTouches[0].clientY + ")";
break;
}
}
}
EventUtil.addHandler(document, "touchstart", handleTouchEvent);
EventUtil.addHandler(document, "touchend", handleTouchEvent);
EventUtil.addHandler(document, "touchmove", handleTouchEvent);
- 手势事件
- gesturestart
- gesturechange
- gestureend
from blog.
内存和性能
起因:由于事件处理程序可以为现代 Web 应用程序提供交互能力,所以开发者会向页面中添加大量的处理程序。(注意:真正引起内存问题的是注册在具体节点的事件处理程序,而不是事件和事件流)
内因:在 JavaScript 中,添加到页面上的事件处理程序数量会直接影响页面的整体运行性能。
- 函数即对象,会占用内存。内存中对象越多,性能越差
- 必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间
事件委托
对“事件处理程序过多”问题的解决方案就是——“事件委托”。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
传统做法:
var item1 = document.getElementById("goSomewhere");
var item2 = document.getElementById("doSomething");
var item3 = document.getElementById("sayHi");
EventUtil.addHandler(item1, "click", function(event){
location.href = "http://www.wrox.com";
});
EventUtil.addHandler(item2, "click", function(event){
document.title = "I changed the document's title";
});
EventUtil.addHandler(item3, "click", function(event){
alert("hi");
});
使用事件委托,在 DOM 树尽量最高的层次上添加一个事件处理程序:
var list = document.getElementById("myLinks");
EventUtil.addHandler(list, "click", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event); // 事件目标是被单击的列表项
switch(target.id){
case "doSomething":
document.title = "I changed the document's title";
break;
case "goSomewhere":
location.href = "http://www.wrox.com";
break;
case "sayHi":
alert("hi");
break;
}
});
移除事件处理程序
每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的 JavaScript 代码之间就会建立一个连接。=>这种链接越多,页面执行起来就越慢(事件委托,可以限制建立的连接数量)。另外,在不需要的时候移除事件处理程序,也是解决这个问题的一种方案。=>内存中留有那些过时不用的“空事件处理程序”,也是造成 Web 应用程序内存与性能问题的主要原因。
造成空事件处理程序的原因有以下情况:
- 从文档中移除带有事件处理程序的元素时。
removeChild()、replaceChild()、innerHTML => 原来添加到元素中的事件处理程序极有可能无法被当作垃圾回收。
<div id="myDiv">
<input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){
// ...
document.getElementById("myDiv").innerHTML = "Processing..."; // 麻烦了!
};
</script>
如果你知道某个元素即将被移除,最好手工移除事件处理程序:
<div id="myDiv">
<input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){
// ...
btn.onclick = null; // 移除事件处理程序
document.getElementById("myDiv").innerHTML = "Processing...";
};
</script>
注意:在事件处理程序中删除目标元素也能阻止事件冒泡,目标元素在文档中是事件冒泡的前提=>如果事先知道将来有可能使用 innerHTML 替换掉页面中的某一部分,那么就可以不直接将事件处理程序添加到该部分的元素中,而通过将事件处理程序指定给较高层次的元素,同样能够处理该区域中的事件。
- 卸载页面的时候
在页面卸载之前没有清理事件处理程序,会滞留在内存中。
最好的做法是在页面卸载之前,先通过 onunload 事件处理程序移除所有事件处理程序。(怎么移除???一个个移除很麻烦,事件委托移除很简单)
这个过程可以理解为,通过 onload 事件处理程序添加的东西,最后都要通过 onunload 事件处理程序将它们移除。
模拟事件
=== 模拟(触发)事件
事件,就是网页中某个特别值得关注的瞬间。
事件经常由用户操作或通过其他浏览器功能来触发,也可以使用 JavaScript 在任意时刻来触发特定的事件。
- DOM 中的事件模拟:document.createEvent()
var btn = document.getElementById("myBtn");
// 创建事件对象
var event = document.createEvent("MouseEvents");
// 初始化事件对象
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
// 触发事件
btn.dispatchEvent(event);
from blog.
Related Issues (20)
- 《JavaScript高级程序设计(第3版)》学习笔记——十七、高级技巧 HOT 3
- 《JavaScript高级程序设计(第3版)》学习笔记——十八、离线应用与客户端存储
- 《JavaScript高级程序设计(第3版)》学习笔记——十九、最佳实践
- 几个奇怪的 CSS 问题 HOT 2
- 《JavaScript高级程序设计(第3版)》学习笔记——二十、新兴的 API
- 用 js 获取网页的各种位置和尺寸
- height:auto 与 transition
- 乱码一通
- 编程字体收集
- http、http1.0、http1.1、https、spdy、http2.0 浅对比总结
- zc
- 事件冒泡与捕获依赖的是什么?
- “慢一点”
- JS 代码片段汇总 HOT 1
- 一段有意思的代码
- #Daily Record# 2020年10月 - 第4周
- #Daily Record# 2020年11月 - 第1周
- #Daily Record# 2020年11月 - 第2周
- #Daily Record# 2020年11月 - 第3周
- #Daily Record# 2020年11月 - 第4周
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from blog.