[摘要]本篇文章给大家带来的内容是关于JavaScript中事件模型的详解(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。事件用户与网页交互是通过事件实现的,事件刚开始是作为分担...
本篇文章给大家带来的内容是关于JavaScript中事件模型的详解(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
用户与网页交互是通过事件实现的,事件刚开始是作为分担服务器负载的一个手段,起初没有统一的规范,直到 DOM2 级,网景和 IE 才开始有各自的 API 规范。
对于事件的触发机制,两个公司都认为页面的触发机制并不只是点击了某个元素,就只触发当前目标元素的事件。
比方说:页面有多个同心圆,当点击最里面的圆时,你其实也点击了包含这个圆外面的那些圆。 两个公司对这点的认同是一致的,但是事件流的传播顺序上采用了不同的两种方案来实现,即事件冒泡和事件捕获。
一、事件冒泡
IE 浏览器从老版本开始就一直支持事件冒泡机制,所谓事件冒泡,指事件流开始是从较为具体的元素接收,一直传播上不具体的元素上。
就是从目标元素传播到父级元素。
<body>
<div id="parent">
<div id="child"></div>
</div>
<script>
function childEventHandler(event) {
console.log(this);
console.log("child 被点击了");
}
function parentEventHandler(event) {
console.log(this);
console.log("parent 被点击了");
}
function bodyEventHandler(event) {
console.log(this);
console.log("body 被点击了");
}
function htmlEventHandler(event) {
console.log(this);
console.log("html 被点击了");
}
function documentEventHandler(event) {
console.log(this);
console.log("document 被点击了");
}
function windowEventHandler(event) {
console.log(this);
console.log("window 被点击了");
}
var bodyEl = document.getElementsByTagName("body")[0];
var htmlEl = document.getElementsByTagName("html")[0];
var win = window;
var parentEl = document.getElementById("parent");
var childEl = document.getElementById("child");
childEl.onclick = childEventHandler;
parentEl.onclick = parentEventHandler;
bodyEl.onclick = bodyEventHandler;
htmlEl.onclick = htmlEventHandler;
document.onclick = documentEventHandler;
win.onclick = windowEventHandler;
</script>
</body>
如下图所示,如果点击了 id 为 child 的元素后,事件流会从 child 一直传播到 window 对象。
所有现代浏览器都支持事件冒泡。
二、事件捕获
由网景公司主导的事件捕获则刚好和事件冒泡相反,事件流开始从不具体的元素触发,然后传播到具体的元素上。简而言之就是从父级元素传播到目标元素。
由于事件捕获是从 IE 9开始支持,不兼容老版本浏览器,所以使用的人比较少。
三、事件流
DOM 规定事件包括三个阶段,事件捕获,处于目标阶段、事件冒泡。
从 IE 9 开始的浏览器规定,事件流的顺序先是事件捕获,会截获到事件,然后是处于目标阶段,实际的目标接收到事件,最后是事件冒泡,可以在这个阶段对事件进行响应。
以之前的 child 元素为例,直到 child 元素接收到事件前(从 window 到 parent),都是事件捕获阶段。到了 child 元素,此时对事件进行处理,随后冒泡到 window 对象上,冒泡阶段也是可以对事件进行处理的。 基于事件冒泡能对事件进行处理的特点,随后将讲到与其有关的事件委托机制。
四、事件绑定
HTML 与 事件的绑定有三种形式:
1.
<div id="child" onclick="console.log('hello');"></div>
2.
var childEl = document.getElementById("child");
childEl.onclick = function() {
console.log('hello');
}
3.
var childEl = document.getElementById("child");
childEl.addEventListener('click', function() {
console.log('hello');
}, false);JavaScript 是单线程的语言,在遇到元素有事件触发时,会在事件队列中寻找有没有与这个事件绑定的函数,如果没有则什么都不做,如果有,则将该函数放到事件队列的前面,等待主线程事件执行完毕后执行。
上述代码第一种绑定,将事件写在 html 中,表现和行为没有解耦,是不建议这样写代码的。
第二种绑定,将事件绑定在元素对象上,这种写法主要是容易发生事件的覆盖。
第三种绑定,首先,第三个参数为布尔值,默认为 false, 表示在事件冒泡阶段调用事件处理程序,如果为 true, 则表示在事件捕获阶段调用事件处理函数。
当我们想处理完一次事件后,将不想在处理该元素的事件绑定时,应该将元素的事件绑定置为空,如果容易发生内存泄漏。
第一种写法:
childEl.onclick = null;
第三种写法:
function eventHandler() {
console.log('hello');
}
childEl.addEventListener('click', eventHandler, false);
childEl.removeEventListener('click', eventHandler, false);五、事件委托(事件代理)
事件委托是利用事件冒泡的性质,事件流开始是从较为具体的元素接收,一直传播上不具体的元素上。
首先,假如有一个列表 ul,每个列表元素 li 点击会触发事件处理程序,显然,如果一个一个地给元素绑定事件, 效率肯定不好。
与此同时,当新增一个元素时,事件不见得会绑定成功。一起来看:
<ul id="menu">
<li class="menu-item">menu-1</li>
<li class="menu-item">menu-2</li>
<li class="menu-item">menu-3</li>
<li class="menu-item">menu-4</li>
</ul>
<input type="button" name="" id="addBtn" value="添加" />
<script>
window.onload = function() {
var menu = document.getElementById("menu");
var item = menu.getElementsByClassName('menu-item');
for (var i = 0; i < item.length; i++) {
item[i].onclick = (function(i) {
return function() {
console.log(i);
}
}(i))
}
var addBtnEl = document.getElementById("addBtn");
addBtnEl.onclick = function() {
var newEl = document.createElement('li');
newEl.innerHTML = "menu-new"
menu.appendChild(newEl);
}
}
</script>新增加的 menu-new,点击发现没有反应,说明事件没有绑定进去,但是我们也并不想,每增加一个新元素,就为这个新元素绑定事件,重复低效率的工作应当避免去做。
我们通过事件委托的思路来想,事件流的传播,目标元素本身依然会有事件,但同时,冒泡出去后,更高层次的 dom 也能处理事件程序。那么,我们只需要给高层次节点绑定事件,通过判断具体是触发的哪个子节点,再做相应的事件处理。
<ul id="menu">
<li class="menu-item">menu-1</li>
<li class="menu-item">menu-2</li>
<li class="menu-item">menu-3</li>
<li class="menu-item">menu-4</li>
</ul>
<input type="button" name="" id="addBtn" value="添加" />
<script>
window.onload = function() {
var menu = document.getElementById("menu");
menu.onclick = function(event) {
var e = event window.event;
var target = e.target e.srcElement;
console.log(e);
switch (target.textContent) {
case "menu-1":
console.log("menu-1 被点击了");
break;
case "menu-2":
console.log("menu-2 被点击了");
break;
case "menu-3":
console.log("menu-3 被点击了");
break;
case "menu-4":
console.log("menu-4 被点击了");
break;
case "menu-new":
console.log("menu-new 被点击了");
break;
}
}
var addBtnEl = document.getElementById("addBtn");
addBtnEl.onclick = function() {
var newEl = document.createElement('li');
newEl.innerHTML = "menu-new"
menu.appendChild(newEl);
}
}
</script>menu 列表的每个子菜单元素的事件都能正确响应,新增的 menu-new 同样也能正确响应事件。
事件委托的好处在于,我们不用给每个元素都一一地手动添加绑定事件,避免重复低效的工作。
其次,事件委托更少得获取 dom, 初始化元素对象和事件函数,能有效减少内存占用。
每当将事件程序指定给元素时,html 代码和 js 代码之间就建立了一个连接,这种连接越多,网页就执行起来越慢,所以事件委托能有效减少连接树,提高网页性能。
总结
用户与网页的交互是通过事件进行的,事件模型分为事件冒泡和事件捕获,事件冒泡的兼容性更好,应用更广,同时通过事件冒泡,可以建立事件委托,提升网页性能。
以上就是JavaScript中事件模型的详解(代码示例)的详细内容,更多请关注php中文网其它相关文章!
微信
分享
网站建设是一个广义的术语,涵盖了许多不同的技能和学科中所使用的生产和维护的网站。
关键词:JavaScript中事件模型的详细说明(代码示例)