事件

推文:

JS阻止冒泡和取消默认事件(默认行为)

深入浅出js事件

js事件大全

事件

事件是可以被 JavaScript 侦测到的用户行为(可以这么理解,事件就是用户行为)。事件通常与函数配合使用(叫做“注册事件监听函数”),当监听到用户有这个行为,执行事件对应的函数,响应用户的行为。

事件举例:

  • 鼠标点击
  • 页面或图像载入
  • 鼠标悬浮于页面的某个热点之上
  • 在表单中选取输入框
  • 确认表单
  • 键盘按键

 

应用怎么通过事件与用户行为交互的

过程为:针对要监听的行为注册事件——用户的某种行为触发事件——执行监听函数——响应用户行为(在设计模式中,这也叫做观察者模式)。

 

比如给页面上一个按钮注册点击事件,事件的处理程序是改变页面背景色,当用户点击的时候(用户行为),就会触发按钮的点击事件,执行处理程序,从而改变页面的背景色。


事件流概念

事件流分为冒泡流和捕获流。

当你点击页面的按钮时,可以认为你点击了这个按钮的同时,也点击了这个按钮的容器(父级元素),也可以认为你点击了页面。

如果在它们身上都注册了点击事件,那么到底是哪个先接收到了事件呢?这就有了事件流的概念,描述的是页面中元素(dom对象)接收事件的顺序。

由于历史原因,不同的浏览器开发团队提出了不同的事件流概念,也就是后来的事件冒泡和事件捕获,这两个描述的事件流顺序刚好是相反的。

 

IE认为事件是冒泡的,从点击的元素开始逐级向上级传递,现在所有的浏览器都默认事件冒泡。

而Netscape Communicator 团队则认为事件是从最外层传递进来的,叫做事件捕获,事件捕获的用意在于在事件到达预定目标之前捕获它。由于老版本的浏览器不支持,因此很少有人使用事件捕获。一般事件冒泡可以放心地使用,在有特殊需要时再使用事件捕获。

 

“ DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段)。但是不同浏览器和版本之间这些划分时机并不一致

 

假如我们点击一个div, 实际上是先点击document,然后点击事件传递到div,而且并不会在这个div就停下,div有子元素就还会向下传递,最后又会冒泡传递回document。

为了兼容更多的浏览器,非特殊情况一般我们都是把事件添加到在事件冒泡阶段。

 

 哪些事件冒泡,哪些事件不冒泡

根据事件类型的场景来分类:

焦点事件

blur,focus:不冒泡,所有浏览器都支持它。

focusin,focusoutt:与 HTML 事件 focus , blur等价,但冒泡。

focus 和 blur最大问题是它们不冒泡。所以在代理场景中下会用另外的focusin和focusoutt。比如在下拉列表等许多常用的效果中,事件代理往往非常的重要,因为许多在各个链接上触发的事件,往往可以很容易的在根节点中进行监听。这个转载了一篇关于focus和blur代理的译文——谈 focus 和 blur 的事件代理。

 

鼠标事件

除了 mouseenter 和 mouseleave,所有鼠标事件都会冒泡,也可以被取消,而取消鼠标事件将会影响浏览器的默认行为。

click,dblclick(双击主鼠标按钮),mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup

移动到后代元素上不会触发的:mouseenter,mouseleave

得到另外一个元素时才触发,不仅仅是针对当前元素而言:mouseout,mouseover(在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。)

页面上的所有元素都支持鼠标事件。

注意:取消鼠标事件的默认行为还会影响其他事件,因为鼠标事件与其他事件是密不可分的关系。比如:

只有在同一个元素上相继触发 mousedown 和 mouseup 事件,才会触发 click 事件;如果mousedown 或 mouseup 中的一个被取消,就不会触发 click 事件。

类似地,只有触发两次 click 事件,才会触发一次 dblclick 事件。如果有代码阻止了连续两次触发 click 事件(可能是直接取消 click事件,也可能通过取消 mousedown 或 mouseup 间接实现),那么就不会触发 dblclick 事件了。

阻止冒泡

 w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true

 

事件的注册

分为在html中注册或者在js中注册,在js中注册也分为两种写法:dom0与dom2级的事件注册

html中注册

缺点是 HTML 与 JavaScript 代码紧密耦合,改动html中代码的同时也得改动js中的代码

<input type="button" value="Echo Username" onclick="alert(username.value)">

js中注册

dom0级事件注册:

var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("Clicked");
};

删除事件:

btn.onclick = null; //删除事件处理程序

dom2级事件注册(addEventListener):三个参数,处理程序里的this都指向元素本身。

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);

最后这个布尔值参数如果是 true,表示在捕获阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序。上面这个程序会在事件冒泡阶段被触发

使用 DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理程序,事件按照注册顺序触发

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
btn.addEventListener("click", function(){
alert("Hello world!");
}, false);

通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()来移除移除时传入的参数与添加处理程序时使用的参数相同。通过 addEventListener()添加的匿名函数将无法移除,上面那种就是匿名函数,下面这种写法就能被移除:

var btn = document.getElementById("myBtn");
var handler = function(){
alert(this.id);
};
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);

IE的事件注册

 attachEvent()和 detachEvent(),两个参数,可注册多个事件,但是事件触发顺序与注册顺序是相反的,都是在冒泡阶段被处理,且处理可程序里的this指向window。事件的移除中同样不能移除匿名函数

IE事件注册与移除的全过程:

var btn = document.getElementById("myBtn");
var handler = function(){
alert("Clicked");
};
btn.attachEvent("onclick", handler);
btn.detachEvent("onclick", handler);

 

阻止事件的默认行为

w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;

要阻止特定事件的默认行为,可以使用 preventDefault()方法,前提是事件对象event的属性 cancelable 设置为 true 。

function preventDefa(e){ 
  if(window.event){ 
    //IE中阻止函数器默认动作的方式  
    window.event.returnValue = false;  
  } 
  else{ 
    //阻止默认浏览器动作(W3C)  
    e.preventDefault(); 
  }  
} 

 

例如,链接的默认行为就是在被单击时会导航到其 href 特性指定的 URL。如果你想阻止链接导航这一默认行为,那么通过链接的
onclick 事件处理程序可以取消它,如下面的例子所示。

var link = document.getElementById("myLink");
link.onclick = function(event){
event.preventDefault();
};

 

事件代理

在JavaScript中,经常会碰到要监听列表中多项li的情形,假设我们有一个列表如下,要实现以下功能:当鼠标点击某一li时,alert输出该li的内容

<ul id="list">
  <li id="item1">item1</li>
  <li id="item2">item2</li>
  <li id="item3">item3</li>
  <li id="item4">item4</li>
</ul>

一个办法是给每个li注册监听事件。

另一个办法就是:把事件处理器添加到一个父级元素上,这样就避免了把事件处理器添加到多个子级元素上。

事件代理机制

事件代理用到了两个在JavaSciprt事件中两个特性:事件冒泡以及目标元素。使用事件代理,我们可以把事件处理器添加到一个元素上,等待一个事件从它的子级元素里冒泡上来,并且可以得知这个事件是从哪个元素开始的。


事件代理实现

第一步,找到目标元素

function getEventTarget(e) {
  e = e || window.event;//事件对象
  return e.target || e.srcElement;
}

第二步,判断目标元素,进行相关操作

function editCell(e){
           var target = getEventTarget(e);
           if(是否是目标元素)
           {
                // DO SOMETHING WITH THE CELL
            }
}

 事件代理推文:【翻译】谈 focus 和 blur 的事件代理

posted @ 2017-07-02 23:09  中二的羊  阅读(191)  评论(0编辑  收藏  举报