Skip to content

js事件总结 #14

@winnieBear

Description

@winnieBear

事件概述

事件是javascript和HTML交互基础, 任何文档或者浏览器窗口发生的交互, 都要通过绑定事件进行交互;

事件响应是异步处理的

事件响应是异步处理的, 当某个事件触发时,不一定马上会得到响应,而是异步处理的,响应的时间是不一定的。

事件的分类

DOM0/原始 事件模型

  • 所有的浏览器都支持
  • 绑定速度最快,直接写在元素上
  • 只能绑定一个handler
  • 没有冒泡还是捕获之说
  • handler中获取event对象各浏览器差异
  • 删除 element.on+event = null;
<!-- DOM0 绑定的方法 -->
<a id="foo" href="javascript;" onclick="alert('did stuff inline');">Click me</a>
<script type="text/javascript">
	// HTML 中的 onclick="" 属性 和 element.onclick 等同
	document.getElementById('foo').onclick = fucntion(){
		alert('did stuff inline');
	}
</script>

DOM2/标准 事件模型

IE事件模型(>=IE9,同时也支持标准事件模型)

标准事件模型与IE的事件模型的区别

选项 标准事件模型 IE事件模型(IE9之前)
支持冒泡和捕获 都支持 只支持冒泡
绑定方法 addEventListener attachEvent(ie5及+)
解绑方法 removeEventListener detachEvent(ie5及+)
事件的名称参数 事件名字,例如click on+事件名字,例如onclick
事件hanlde中对事件对象的获取 事件处理函数的第一个参数或window.event(FF不支持) 通过window.event或事件处理函数的第一个参数
事件hanlde中的this 事件绑定的对象 window
阻止冒泡的方法 event.stopPropagation(); event.cancelBubble = true;
阻止默认行为的方法 event.preventDefault(); event.returnValue = false;
事件target event.target event.srcElement
事件relatedTarget event.relatedTarget event.fromElement/event.toElement
冒泡过程中currentTarget event.currentTarget
单个元素添加多个事件处理程序,执行的顺序 执行顺序按照它们添加的顺序执行 执行顺序按照添加的顺序相反的顺序执行
  • 支持冒泡和捕获

    • 支持冒泡和捕获
    • 只支持冒泡
  • 绑定方法

    • addEventListener
    • attacthEvent
     var eventUtil = {
     on : function(el, type, handler) {
         if(el.addEventListener) {
             el.addEventListener(type, handler, false);
         }else if( el.attachEvent ) {
             el.attachEvent("on"+type, handler);
         }else{
             el["on"+type] = handler;
         }
     },
     off : function(el, type, handler) {
         if( el.removeEventListener ) {
             el.removeEventListener(type, handler, false)
         }else if( el.detachEvent ) {
             el.detachEvent(type, handler);
         }else{
             el["on"+type] = null;
         }
     }
     };
  • 解绑方法

    • removeEventListener
    • detachEvent
  • 事件的名称参数

    • 事件名字,例如click
    • on+事件名字,例如onclick
  • 事件hanlde中对事件对象的获取

    • 支持标准事件模型的浏览器,不管用addEventListener还是ele.onclick方式绑定事件,通过事件处理的handle函数第一个参数就可以获取event对象;
    • 而IE不支持标准事件模型的浏览器(<IE9),ele.onclick方式绑定事件时,只能用window.event来获取
     function handle(event){
     	var event = event || window.event;
     	//...
     }
    
     ele.attachEvent && ele.attachEvent("onclick", handler);
    ele.addEventListener && ele.addEventListener("click", handler, false);
    ele.onclick = handler;
  • 事件hanlde中的this

    • addEventListener绑定事件的handle中的this指向被绑定的元素ele
    • attacthEvent绑定事件的handle中的this指向window,而不是被绑定的元素ele
  • 阻止冒泡的方法

    • event.stopPropagation();
    • event.cancelBubble = true;
     function handle(event){
     	var event = event || window.event;
    
     	if(event.stopPropagation){
     		event.stopPropagation();
     	}else
     	{
     		event.cancelBubble= true;
     	}
    
     	//...
     }
  • 阻止默认行为的方法

    • event.preventDefault();
    • event.returnValue = false;
     function handle(event){
     	var event = event || window.event;
    
     	if(event.preventDefault){
     		event.preventDefault();
     	}else{
     		event.returnValue = false;
     	}
     	//...
     }
  • 事件target

    • event.target
    • event.srcElement
     function handle(event){
     	var event = event || window.event;
     	var target = event.target || event.srcElement;
     	//...
     }
  • 事件的relatedTarget

    • relatedTarget
    • fromElement/toElement
     function handle(event){
     	var event = event || window.event;
     	var relatedTarget = event.relatedTarget || event.fromElement/*toElement*/;
     	//...
     }

事件对象的其他参数

冒泡和捕获

冒泡和捕获

冒泡带来的便利和不便

  • 通过冒泡机制来实现事件代理
  • 冒泡对某些事件的处理带来困扰例如mouseover/mouseout

事件代理

因为事件有冒泡机制,所有子节点的事件都会顺着父级节点跑回去,所以我们可以通过监听父级节点来实现监听子节点的功能,这就是事件代理。

使用事件代理主要有两个优势:

  • 减少事件绑定,提升性能。之前你需要绑定一堆子节点,而现在你只需要绑定一个父节点即可。减少了绑定事件监听函数的数量。
  • 动态变化的 DOM 结构,仍然可以监听。当一个 DOM 动态创建之后,不会带有任何事件监听,除非你重新执行事件监听函数,而使用事件监听无须担忧这个问题。

不能冒泡的事件

  • focus/blur事件不冒泡,但focusin and focusout Fire at the same time as focus and blur会冒泡。
    from

  • mouseenter/mouseleave(only ie/opera 支持)不冒泡,在mouseover/mouseout时触发会冒泡

  • submit/reset事件
    功能:监听表单的提交/重置;

    在IE6到IE8下只会冒泡到当前提交表单所在的form标签中,也就说document下直接代理监听多个表单提交会有兼容性问题。

  • change事件
    功能:监听元素value值的改变,input和select 在blur才触发;

    change事件在IE6到IE8,chrome,safari下都不会冒泡,也不能像focus和blur一样可以用focusin和focusout替代,在IE下也不能通过设置captrue实现对事件的捕获,其他高级浏览器下可以。

  • select事件
    功能:监听文本域中文字的选中。

    select事件在IE6到IE8,chrome,safari下都不会冒泡,但是比change好的一点是,在IE下可以使用selectstart替代,而在高级浏览器中可以直接设置captrue为捕获即可。

键盘事件

键盘事件的触发流程

一个典型的按键输入,依次触发的事件依次是

  • keydown
  • keypress
  • keypress事件触发后,input元素更新value属性
  • keyup

如果一个按键被按下并重复按下,则可能在keydown和keyup事件之间触发多个keypress事件。

键盘事件的兼容性

选项 其他浏览器 IE
不能打印的功能按键(退格,回车,escape)和箭头方向键,翻页键,F1-F12 有时候会触发keypress事件 IE只有当按键有一个ASCII码的时候,才会触发keypress
获取按键码的事件属性 keyeCode/charCode keyCode
keydown/keyup keyeCode为虚拟按键码/charCode为0 keyCode为虚拟按键码
keypress keyeCode为虚拟按键码/charCode为虚拟按键码,FF为0 keyCode为字符的ASCII值
输入中文时 不触发keypress,大部分浏览器触发keydown,keycode为229 不触发keypress,触发keydown,keycode为229

常见案例

  • 过滤输入框的字符只能输入特定的字符
    • keyup + change(粘贴)
  • 搜索框的suggest
    • keyup + paste(粘贴) ?

键盘事件的兼容性列表

鼠标事件

鼠标事件的触发流程

一个典型的鼠标拖动操作,依次触发的事件依次是

  • mouseover
  • mousedown
  • mousemove
  • mouseup
  • click
  • mouseout

如果中间鼠标移动,将会触发多个mousemove事件。

鼠标事件的问题

  • mousedown/mouseup不一定都会触发
    当按下鼠标进入目标或按下鼠标移出目标区域

  • mouseover和mouseout的冒泡问题
    适当的用mouseenter和mouseleave替代mouseover和mouseout

jQuery/zepto的事件绑定

//绑定
$(ele).on( events [, selector ] [, data ], handler );

//触发事件
$(elementA).trigger( events );

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions