首页 > 代码库 > 13章 事件

13章 事件

 
 
发展
IE3和Netscape Navigator2    :       作为分担服务器负载的一种手段;
IE4和Naviscape4    :    提供了相似却不相同的API;
DOM2规范制定    :    开始尝试标准化DOM事件;
DOM2实现    :    IE9、Firefox、Opera、Safari和Chrome全部实现‘DOM2级事件’核心部分;    
DOM3级出现    :    API变得更加繁琐。
13.1    事件流
    13.1.1    事件冒泡    :    最具体的元素->...->document
            
  • 支持情况    :    所有浏览器。

  • 差异       :    

浏览器表现
IE5.5-最具体的元素->...->body->document
IE9、Firefox、Chrome、Safari最具体的元素->...->body->html->document->window   

    13.1.2    事件捕获    :      document->html->body->...->最具体的元素

        [DOM2级规范]

        
  • 支持情况:    IE9、Safari、Chrome、Opera、Firefox

  • 不支持情况    :    所有老版本浏览器

    13.1.3    DOM事件流
    1. 事件捕获阶段    :    为截获事件提供机会

    2. 处于目标阶段    :    实际的目标接收到事件

    3. 事件冒泡阶段    :    冒泡阶段

支持情况:    IE9、Safari、Chrome、Opera、Firefox
13.2    事件处理程序
    13.2.1    HTML事件处理程序
        特点
  • 会创建一个封装着元素属性值的函数;

    • this    :    当前dom

    • event    :    事件对象

  • 扩展了作用域;

//形象说明作用域的扩展情况function(){    with(document){        with(this){            //HTML标签中的代码相当于在这里执行        }    }}//表单的情况function(){    with(document){        with(this.form){            with(this){                //HTML标签中的代码相当于在这里执行            }        }    }}
        使用
 
  • 方式一    :    直接在标签中嵌入JS代码

不能使用未经转义的HTML语法字符!
<input type=‘button‘ value=http://www.mamicode.com/‘Click Me‘ onclick="alert(‘Clicked‘)" />
  • 方式二    :    调用其他地方定义的脚本

<script>    function showMessage(){        alert(‘Hello world!‘);    }</script><input type=‘button‘ value=http://www.mamicode.com/‘Click Me‘ onclick="showMessage()" />
        缺点
  • 解析不及时引发错误    :    如果函数被定义在最底部,如果用户在页面解析注册的方法之前就被调用将发生错误;

<!-- try-catch避免引发错误 --><input type=‘button‘ value=http://www.mamicode.com/‘Click Me‘ onclick=‘try{showMessage();}catch(e){}‘ />
  • 扩展事件处理程序的作用域链在不同 浏览器中会导致不同结果;

  • HTML代码和JavaScript代码耦合。

    13.2.2    DOM0级事件处理程序    :    将函数赋值给一个事件处理程序属性
        特点
  • DOM0级方法指定的事件处理程序被认为是元素的方法,因此程序中的this引用当前元素;

  • 这种事件处理程序在事件流的冒泡阶段处理;

  • 每个元素(包括window和document)都有自己的的事件处理程序。

var btn = document.getElementById(‘myBtn‘);btn.onclick = function(){    alert(this.id);    //‘myBtn‘};btn.onclick = null;    //删除通过DOM0级方法指定的事件处理程序 
    13.2.3    DOM2级事件处理程序
        两个方法
  • addEventListener()    :    添加事件,3个参数,要处理的事件名、作为事件处理处理程序的函数、布尔值(true表示捕获阶段;false表示冒泡阶段)

    • 依附元素的作用于;

    • 可以添加多个事件处理程序,事件触发后按添加的顺序执行;

    • addEventListener()添加的事件处理程序只能使用removeEventListener()来移除;

    • 移除时传入的参数与添加处理程序使用相同的参数;

    • 添加的匿名函数无法移除。

  • removeEventListener()    :    移出

    addEventListener()添加的事件处理程序,参数和

     

    addEventListener()

     保持一致     

var btn = document.getElementById(‘myBtn‘);//添加多个事件处理程序btn.addEventListener(‘click‘, function(){    alert(this.id);},false);btn.addEventListener(‘click‘, function(){    alert(‘Hello World!‘);},false);//演示移除事件处理程序var handler = function(){    alert(this.id);};btn.addEventListener(‘click‘, handler, false);btn.removeEventListener(‘click‘, handler, false);   
        将事件添加到事件的冒泡阶段而不是捕获阶段可以最大程度兼容各种浏览器,除非需要在事件到达目标之前截获事件。
IE9FirefoxSafariChromeOpera
    13.2.4    IE事件处理程序
        两个方法
  • attachEvent()    :    添加事件,两个参数,事件处理程序名称、事件处理函数

    • IE8-只支持事件冒泡,因此会被添加到冒泡阶段;

    • 事件名带‘on‘前缀;

    • 事件处理程序在全局作用域中运行,this等于window;

    • 可以添加多个事件处理程序,事件触发后按与添加的相反的顺序执行;   

    • attachEvent() 添加的事件处理程序只能使用detachEvent()来移除;

    • 移除时传入的参数与添加处理程序使用相同的参数;

    • 添加的匿名函数无法移除。

  • detachEvent()    :    移除通过attachEvent()添加的事件处理函数

var btn = document.getElementById(‘myBtn‘);var handler = function(){    alert(this == window);    //true};btn.attachEvent(‘onclick‘, handler);btn.detachEvent(‘onclick‘, handler);
IEOpera
    13.2.5    跨浏览器的事件处理程序
/*** DOM2>IE>DOM0* param{object} element - dom节点对象* param{string} type - 事件名称* param{boolean} handler - 函数的引用*/var EventUtil = {    //添加事件处理程序    addHandler:    function(element, type, handler){        if(element.addEventListener){    //DOM2            element.addEventListener(type, handler, false);        }else if(element.attachEvent){    //IE8-            element.attachEvent(‘on‘+type, handler);        }else{    //DOM0            element[‘on‘+type] = hanler;        }    },    //移除事件处理程序    addHandler:    function(element, type, handler){        if(element.removeEventListener){    //DOM2            element.addEventListener(type, handler, false);        }else if(element.detachEvent){    //IE8-            element.detachEvent(‘on‘+type, handler);        }else{    //DOM0            element[‘on‘+type] = null;        }    }};
该方法没有考虑只支持DOM0级浏览器只支持一个事件处理程序的问题,如果多次绑定处理程序,只有最后一个有效。
13.3    事件对象    :    触发DOM上的某个事件是会产生一个事件对象event(DOM0或DOM2),包含所有与时间有关的信息。
    特点
  • 所有浏览器都支持event对象,但支持方式不同;

  • 只在事件处理程序执行期间存在,执行完毕后被销毁;

  • 不同事件类型可用的属性和方法不同,都包括的成员如下:

        特别成员
  • event.type    :    事件类型

var btn = document.getElementById(‘myBtn‘);var handler = function(event){    switch(event.type){        case "click":            alert(‘Clicked‘);            break;        case "mouseover":            event.target.style.backgroundColor = ‘red‘;            break;        case "mouseout":            event.target.style.backgroundColor = ‘‘;            break;    }};btn.onclick = handler;btn.onmouseover = handler;btn.onmouseout  = handler;
 
  • event.target    :    事件的实际目标(最具体的那个元素)

  • event.currentTarget    :    和this相同,注册事件的那个元素

  • event.eventPhase     :    事件当前所在的事件流的阶段

    • 1:    捕获阶段调用事件处理程序

    • 2:    事件处理程序处在目标对象上

    • 3:    冒泡阶段调用事件处理程序

var btn = document.getElementById(‘myBtn‘);//捕获阶段document.body.addEventListener(‘click‘, function(event){    alert(event.eventPhase);    //1},true);//处于目标阶段btn.onclick = function(event){    alert(event.eventPhase);    //2};//冒泡阶段document.body.addEventListener(‘click‘, function(event){    alert(event.eventPhase);    //3},false);
  • event.preventDefault()    :    取消默认行为

  • event.stopPropagation()    :    立即停止事件在DOM层次中的传播,即取消进一步的事件捕获或冒泡

    13.3.2    IE中的事件对象
        特点
  • 访问IE中的event对象的方式取决于指定事件处理程序的方法

        访问方式
  • window.event(DOM0级方法)

var btn = document.getElementById(‘myBtn‘);btn.onclick = function(){    var event = window.event;    alert(event.type);    //‘click‘};
  • 作为参数对象(attachEvent())

var btn = document.getElementById(‘myBtn‘);btn.attachEvent(‘onclick‘, function(event){    alert(event.type);    //‘click‘});
  • 直接访问event(HTML中)

<input tyep=‘button‘ value=http://www.mamicode.com/‘Click Me‘ onclick=‘alert(event.type)‘ />
        属性/方法
    
    13.3.3    跨浏览器的事件对象
    创建一个兼容的操作事件对象的工具对象    :    因为兼容IE不支持阻止事件捕获
var EventUtil = {    /**    * 用来添加事件处理程序的方法    * param{object} element - dom    * param{string} type - 事件名称    * param{function} handler - 函数引用    */    addHandler:    function(element, type, handler){        if(element.addEventListener){    //DOM2            element.addEventListener(type, handler, false);        }else if(element.attachEvent){    //IE8-            element.attachEvent(‘on‘+type, handler);        }else{    //DOM0            element[‘on‘+type] = hanler;        }    },     /**    * 用来移除事件处理程序的方法    * param{object} element - dom    * param{string} type - 事件名称    * param{function} handler - 函数引用    */    addHandler:    function(element, type, handler){        if(element.removeEventListener){    //DOM2            element.addEventListener(type, handler, false);        }else if(element.detachEvent){    //IE8-            element.detachEvent(‘on‘+type, handler);        }else{    //DOM0            element[‘on‘+type] = null;        }    },    /**    * 获得事件对象的方法    * param{object} event - 事件处理程序执行时产生的事件对象(如果有的话)    * return{object} 事件对象    */    getEvent:    function(event){        return event ? event : window.event;    },    /**    * 获得触发事件的目标的方法    * param{event} event    - 事件对象    * return{object} dom    - 触发事件的节点        */    getTarget:    function(event){        return event.target || event.srcElement;    },    /**    * 取消默认动作    * param{object} event    -事件对象    */    preventDefault:    function(event){        if(event.preventDefault){            event.preventDefault();        }else{            event.returnValue = http://www.mamicode.com/false;        }    },    /**    * 阻止事件冒泡(或捕获)    * param{object} event    -事件对象    */    stopPropagation:    function(event){        if(event.stopPropagation){            event.stopPropagation();        }else{            event.cancelBubble =  true;        }    }};
    使用上述快跨览器的工具
btn.onclick = function(event){    event = EventUtil.getEvent(event);    //    确保在不同浏览器都能获得event    var target = EventUtil.getTarget(event);    //确保获得target    EventUtil.preventDefault(event);    //确保清除默认动作    EventUtil.stopPropagatiom(event);    //阻止传播    };
13.4    事件类型
  • DOM2级事件

  • DOM3级事件(以DOM2为基础)

  • UI事件

    • 焦点事件

    • 鼠标事件

    • 滚轮事件

    • 文本事件

    • 键盘事件

    • 合成事件

    • 变动事件

    • 变动名称事件

  • HTML5定义的一组事件

  • DOM和BOM中实现的其它专有事件(没有规范)

    13.4.1    UI事件
        历史:    出现在DOM规范之前,被规范保留。
        分类:    现有的UI事件
                  
事件名称DOM触发时机备注 
DOMActive   任何元素元素已经被用户操作激活被DOM3废弃
load



window页面加载完后HTML事件


框架集所有框架都加载完毕
<img>图像加载完毕
<object>嵌入的内容加载完毕
unload


window页面完全卸载HTML事件   



<img>   无法加载图片
框架集   所有框架都卸载
<object>   嵌入的内容卸载完毕
abort<object>      用户停止下载,嵌入的内容没有加载完HTML事件   
error


windowJavaScript错误HTML事件   



<img>无法加载图像
<object>无法加载嵌入内容
框架集有框架无法加载
select<input>用户选择文本框一个或多个字符HTML事件   

<textarea>用户选择文本框一个或多个字符    
resizewindow或框架窗口或框架变化HTML事件   
scroll带滚动条的元素用户滚动带滚动条的元素中的内容HTML事件 
 <body>元素中包含加载
元素的滚动条
        为UI事件定义事件处理程序
  • load事件

        标准load事件实现
         案例一:以body为例
方式一:    JS(推荐)
    • 使用了跨浏览器的脚本;

    • 传入的event不包含有关这个时间的任何附加信息;

    • 兼容DOM时,event.target会被设置为document;IE不会为其设置srcElement属性;

    • "DOM2级事件"规范应该在document上而不是window上触发load事件,但所有浏览器都在window上面实现了该事件(确保向后兼容)。

EventUtil.addHandler(window, ‘load‘, function(event){    alert(‘Loaded!‘);});
方式二:    为元素添加onload属性
<!DOCTYPE html><html><head>    <title>Load Event Example</title></head><body onl oad=‘alert(‘Loaded!‘)‘></body></html>
        案例二:img
方式一
var image = document.getElementById(‘myImage‘);EventUtil.addHandler(image, ‘load‘, function(event){    event = EventUtil.getEvent(event);    alert(EventUtil.getTarget(event).src);});
方式二
<img src=http://www.mamicode.com/‘smile.gif‘ onl oad=‘alert(‘Image loaded.‘)‘>
        案例三:创建新的<img>元素,同时指定一个事件处理程序
    • 要在window上的onload事件触发后才添加DOM中,否则document.body会报错;

    • 一旦设置了src属性,新创建的图像就开始加载图像,和是否添加到文档中无关;

方式一:    DOM的方式
    • [IE8-]没有添加到DOM中的节点触发load事件时不会生成event对象。

EventUtil.addHandler(window, ‘load‘, function(event){    var image = document.createElement(‘img‘);    EventUtil.addHandler(image, ‘load‘, function(event){        event = EventUtil.getEvent(event);        alert(EventUtil.getTarget(event).src);    });    document.body.appendChild(image);    image.src  = ‘smile.gif‘;});
方式二:    Image对象
    • 可以像使用<img>元素一样使用Image对象(并非所有浏览器都将Image对象实现为<img>);

    • 无法添加到DOM中;

    • 【IE8- 】Image对象触发load事件不会生成event对象。

EventUtil.addHandler(window, ‘load‘, function(){    var image = new Image();    EventUtil.addHandler(image, ‘load‘, function(event){        alert(‘Imaeg loaded!‘);    });});
       案例四:    script元素
  • 指定src属性并将元素添加到文档后才开始下载。

EventUtil.addHandler(window, ‘load‘, function(){    var script = document.createElement(‘script‘);    EventUtil.addHandler(script, ‘load‘, function(event){        alert(‘Loaded‘);    });    script.src = http://www.mamicode.com/‘exaple.js‘;    document.body.appendChild(script);});
        兼容性问题
浏览器版本script元素onload事件event.target
大多数浏览器支持<script>节点
Firefox3-支持document
IE8-不支持 
        案例五:    link属性
  • 和script类似

        兼容性问题
IEOpera
 
    2.    unload事件
 
  • 发生时机举例:只要用户从一个页面切换到另外一个页面,就会发生unload事件;

  • 用途举例:清除引用避免内存泄漏;

  • DOM2级事件规定应该在<body>元素而不是window对象上触发unload事件。

方式一:    JS
EventUtil.addHandler(window, ‘unload‘, function(event){    alert(‘Unloaded‘);});
方式二:    HTML
<!DOCTYPE html><html><head>    <title>Unloaded</title></head><body onunload="alert(‘unloaded!‘)"></body></html>
    3.    resize事件
  • 浏览器最大化最小化时也会触发resize事件。

方式一:    JS
EventUtil.addHandler(window, ‘resize‘, function(event){    alert(‘Resized‘);});
方式二:    HTML
<!DOCTYPE html><html><head>    <title>Unloaded</title></head><body onresize="alert(‘resized!‘)"></body></html>
event差异
浏览器event.target备注
兼容DOM的document 
IE8-event没有任何属性 
 
行为差异
浏览器触发时间
IE、Safari、Chrome、Opera窗口变化1像素时
Firefox用户停止调整窗口大小时
    4.    scroll事件
  • 在window对象上触发,表现的是页面上元素的变化。

模式浏览器元素具体表现
混杂模式所有bodyscrollLeft和scrollTop
标准模式Safaribody跟踪滚动位置
其它html跟踪滚动位置
//输出页面的垂直滚动位置,根据不同模式使用不同的元素EventUtil.addHandler(window, ‘scroll‘, function(event){    if(document.compatMode == ‘CSSCompat‘){        alert(document.documentElement.scrollTop);    }else{        alert(document.body.scrollTop);    }});
    13.4.2    焦点事件
  • 触发:  页面获得或失去焦点;

  • 使用: 利用这些事件并与document.hasFocus()方法及document.activeElement属性配合来知晓用户在页面上的行踪;

  • 顺序:以焦点由A元素移动到B元素为例

    1. focusout(A)

    2. focusin(B)

    3. blur(A)

    4. DOMFocusOut(A)

    5. focus(B)

    6. DOMFocusIn(B)

  • 检测支持情况

var isSupported = document.implementaation.hasFeature(‘FocusEvent‘,‘3.0‘);
 焦点事件名    冒泡触发兼容性备注
blur失去焦点所有DOM3级事件(来自IE)
focus获得焦点DOM3级事件(来自IE)     
DOMFocusIn是  获得焦点OperaDOM3级事件中用focusin取代
DOMFocusOut失去焦点DOM3级事件中用focusout取代
focusin获得焦点IE5.5+、Safari5.1+、
Opera11.5+、Chrome
 
focusout失去焦点 
 
    13.4.3    鼠标与滚轮事件
        DOM3级
鼠标/滚轮事件名称冒泡触发兼容性备注
click单机主鼠标按钮(通常是左键)或键盘回车键  
dbclick双击主鼠标按钮非DOM2 
mousedown用户按下任意鼠标按钮时  
mouseenter鼠标光标从元素外部首次移动到元素范围之内IE、Firefox9+、Opera(非DOM2  )

非子元素
mouseleave鼠标光标移动到元素之外 
mousemove



鼠标光标在元素内移动时重复触发 非键盘


mouseout从一个元素移动到里一个元素(父/子/兄弟) 
mouseover从目标元素外部移动到另一个元素边界内 
mouseup释放鼠标按钮 
  • 冒泡可以被取消,但会影响其他事件;

  • 事件执行顺序(以双击鼠标主键为例):

 
标准IE8(会跳过括号中的时间)
  1. mousedown

  2. mouseup

  3. click

  4. mousedown

  5. mouseup

  6. click

  7. dbclick

  1. mousedown

  2. mouseup

  3. click

  4. (mousedown)

  5. mouseup

  6. (click)

  7. dbclick

  • click和dbclick事件会依赖其它先行时间的触发;mousedown和mouseup不受其它事件影响;

检测
  • DOM2

var isSupported = document.implementation.hasFeature(‘MouseEvents‘, ‘2.0‘);
  • DOM3

var isSupported = document.implementation.hasFeature(‘MouseEvent‘, ‘2.0‘); 
           鼠标事件信息 
        1.    客户区(Client)坐标位置:浏览器视窗作为参照
 
属性作用兼容性特点
event.clientX事件发生时鼠标指针在视口中的水平坐标所有不包括滚动的距离
event.clientY事件发生时鼠标指针在视口中的垂直坐标
var div = document.getElementByid(‘myDiv‘);EventUtil.addHandler(div, ‘click‘, function(event){    event = EventUtil.getEvent(event);    alert(‘Client coordinates:‘ + event.clientX + ‘,‘ + event.clientY);});
        2.    页面(Page)坐标位置
 
属性作用兼容性特点
event.pageX事件发生时鼠标指针在页面中的水平坐标IE8-之外包括滚动的距离
event.pageY事件发生时鼠标指针在页面中的垂直坐标
            方式一:兼容IE8-,兼容混杂模式(document.body)和标准模式(document.documentElement)
var div = document.getElementByid(‘myDiv‘);EventUtil.addHandler(div, ‘click‘, function(event){    event = EventUtil.getEvent(event);    var pageX = event.pageX, pageY = event.pageY;    if(pageX === undefined){        pageX = event.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft);         pageY = event.clientY + (document.body.scrollTop || document.documentElement.scrollTop);    }    alert(‘Page coordinates:‘ + pageX + ‘,‘ + pageY);});
            方式二:其它浏览器
var div = document.getElementByid(‘myDiv‘);EventUtil.addHandler(div, ‘click‘, function(event){    event = EventUtil.getEvent(event);    alert(‘Page coordinates:‘ + event.pageX + ‘,‘ + event.pageY);});
        3.    屏幕(Screen)坐标位置
属性作用兼容性特点
event.screenX事件发生时鼠标指针在屏幕中的水平坐标IE8-之外包括滚动的距离
event.screenY事件发生时鼠标指针在屏幕中的垂直坐标
var div = document.getElementByid(‘myDiv‘);EventUtil.addHandler(div, ‘click‘, function(event){    event = EventUtil.getEvent(event);    alert(‘screen coordinates:‘ + event.screenX + ‘,‘ + event.screenY);});
        4.    修改键    :    按下鼠标时键盘上的某些键会影响所要采取的操作
修改键DOM规定的对应属性兼容性
Shiftevent.shiftKey所有(IE8-除外)


Ctrlevent.ctrlKey
Altevent.altKey
meta(win或Cmd)event.metaKey
//如果某个修改键被按下,event中对应的属性值为truevar div = document.getElementById(‘mDiv‘);EventUtil.addHandl(div, ‘click‘, function(event){    event = EventUtil.getEvent(event);    var keys = new Array();    if(event.shiftKey){        keys.push(‘shift‘);    }    if(event.altKey){        keys.push(‘alt‘);    }    if(event.ctrlKey){        keys.push(‘ctrl‘);    }    if(event.metaKey){        keys.push(‘meta‘);    }    alert(‘Keys:‘ + keys.join(‘,’));} );
        5.    相关元素    :    mouseover和mouseout事件触发时,除住目标外还会涉及其它相关元素。
  • 获取相关元素:

event的属性事件属性值触发时机兼容性
relatedTargetmouseoverA元素的dom鼠标从A元素进入B(目标)元素IE8-不支持
mouseoutB元素的dom鼠标从A(目标)元素离开  
fromElementmouseoverA元素的dom鼠标从A元素进入B(目标)元素IE(包括IE8-)
toElementmouseoutB元素的dom鼠标从A(目标)元素离开  
var EventUtil = {    //省略其它代码        /**    * 跨浏览器获得相关元素的方法    */    getRelatedTarget: function(event){        if(event.relatedTarget){            return event.relatedTarget;        }else if(event.toElement){            return event.toElement;        }else if(event.fromElement){            return null;        }    },    //省略其它代码};
var div = document.getElementById(‘myDiv‘);EventUtil.addHandler(div, ‘mouseout‘, function(){    event = EventUtil.getEvent(event);    var target = EventUtil.getTarget(event);    var relatedTarget = EventUtil.getRelatedTarget(event);    alert(‘Mouse out of ‘ + target.tagName + ‘ to ‘ + relatedTarget.tagName);});
    6.    鼠标按钮(mousedown 和 mouseup发生时了解哪些鼠标按钮被ianxia)
event.buttonDOMIE8-
0没有按下按钮
1
2
3主+次 
4 
5主+中 
6次+中 
7主+中+次 
var EventUtil = {    //省略其它代码    /**    * 检测是否兼容DOM并规范化对相应的值规范化    */    getButton: function(event){        if(document.implementation.hasFeature(‘MouseEvents‘, ‘2.0‘)){            return event.button;        }else{            switch(event.button){                case 0:                case 1:                 case 3:                case 5:                case 7:                    return 0;                case 6:                    return 2;                case 4:                    return 1;                               }        }    },    //省略其它代码};var div = document.getElementById(‘myDiv‘);EventUtil.addHandler(div, ‘mousedown‘, function(event){    event = EventUtil.getElement(event);    alert(EventUtil.getButton(event));});
    7.    更多的事件信息
DOM2级事件IE
event属性类型备注event属性类型备注
detailnumber给定位置上发生点击的数量altLeftboolean是否按了Alt
   ctrlLeftboolean是否按了Ctrl
   offSetXnumber光标相对于目标元素边界的x坐标
   offSetYnumber光标相对于目标元素边界的y坐标   
   shiftLeftboolean是否按下shift键
    8.    鼠标滚轮事件(mousewheel)
  •  IE6首先实现

event属性浏览器冒泡到表现
wheelDeltaIE8document向前滚动120的倍数;向后滚动-120的倍数
IE9、Opera、Chrome、Safariwindow
//解决Opera 9.5之前的版本wheelDelta值正负点到的问题EventUtil.addHandler(document, ‘mousewheel‘, function(event){    event = EventUtil.getEvent(event);    var delta = (client.engine.opera && client.opera < 9.5 ?-event.wheelDelta.opera:event.wheelDelta);    alert(delta);});
/*** 兼容opera9.5-的获取wheelDelta值得方法*/var EventUtil = {    //省略了其它代码    getWheelDelta: function(event){        if(event.wheelDelta){            return (client.engin.opera && client.engin.opra < 9.5 ? -event.wheelDelta : event.wheelDelta);        }else{            return -event.detal * 40;        }    },};
    9.    触摸设备
  • 不支持dbclick事件。双击浏览器窗口会放大画面,而且没有办法改变;

  • 轻击可单击元素会触发mousemove;

  • mousemove事件也会触发mouseover和mouseout事件;

  • 两个手指放在屏幕上且页面随手指一动而滚动时会触发mousewheel和scroll事件。

    10.    无障碍性问题
不建议使用click之外的其他鼠标事件展示功能或引发代码执行;
不建议使用onmousedown,因为屏幕阅读器中无法触发mousedown事件;
不推荐使用的事件:
事件名不推荐的原因
click之外的鼠标事件无法通过键盘触发
onmousedown屏幕阅读器无法触发该事件
onmouseover
dbclick无法通过键盘触发
 
www.webaim.org
    13.4.4    键盘与文本事件
    支持修改键,IE不支持metaKey.
  •     键盘事件(3)

  1. 位数  77DOM0    :    对键盘事件的支持主要遵循DOM0级;

  2. DOM2    :    最终定稿时删除了相应的内容;

  3. DOM3    :    为键盘事件制定了规范,IE9率先实现。

键盘事件触发表现兼容性
keydown按下任意键按住不放会重复触发 
keypress按下字符键(包括Esc)Safari3.1-(非字符键也会触发)
keyup释放键盘上的键  
  • 文本事件(1)

文本事件触发表现兼容性
textInput文本插入文本框之前keydown->keypress->textInput->keyup 
    1.    键码
event属性对应事件兼容性
keyCodekeydown 和 keyupASCLL码中对应小写字母或数字的编码相同(分号按键存在兼容性问题)DOM和IE
var textbox = document.getElementById(‘myText‘);EventUtil.addHandler(textbox, ‘keyup‘, function(event){        event = EventUtil.getEvent(event);        alert(event.keyCode);});
    2.    字符编码
event属性对应事件兼容性
charCodekeypress按下的键对应的ASCLLIE9、Firefox、Chrome、Safari
  • 不考虑兼容

var textbox = document.getElementById(‘myText‘);EventUtil.addHandler(textbox, ‘keypress‘, function(event){        event = EventUtil.getEvent(event);        alert(event.charCode);});
  • 考虑兼容

var EventUtil = {    //省略的代码        getCharCode: function(event){        if(typeof event.charCode == ‘number‘){            reutrn event.charCode;        }else{            reutrn event.keyCode;        }    },        //省略的代码};
    3.    DOM3级变化
 
  • event中删除的成员

event属性对应事件兼容性
charCodekeypress按下的键对应的ASCLLIE9、Firefox、Chrome、Safar
  • event中添加的成员

event成员对应事件兼容性
key
keypress

文本字符或键的名字(非字符)IE9支持
char文本字符或null(非字符)IE9不支持
keyIdentifier(非DOM3)‘U+000‘字符串或键的名字(非字符)Sfari 5 和 Chrome
locationnumber(代表键盘区域的位置)IE9
keyLocation有BUGSafari和Chrome
getModifierState()boolean,检测某个修改键是否被按下IE9唯一支持
//跨浏览器获得键盘字符var textbox = document.getElementById(‘myText‘);EventUtil.addHandler(textbox, ‘keypress‘, function(event){    event = EventUtil.getEvent(event);    var identifier = event.key || event.keyIdentifier;    if(identifier){        alert(identifier);    }});
//检测某个修改键是否被按下var textbox = document.getElementById(‘myText‘);EventUtil.addHandler(textbox, ‘keypress‘, function(event){    event = EventUtil.getEvent(event);    if(event.getModifiedState){        alert( event.getModifiedState(‘Shift‘));    }});
 
    4.    textInput事件
相关属性有效元素事件来源兼容性
event.data可编辑区域textInput(在可编辑区域输入字符时)用户输入的字符(非字符编码)DOM3级事件IE9+、Safari、Chrome
event.textInput0-9(表示输入到文本框中的方式)仅IE
 
//获得用户输入的字符var textbox = document.getElementById(‘myText‘);EventUtil.addHandler(textbox, ‘textInput‘, function(event){    event = EventUtil.getEvent(event);    alert(event.data);});
    5.    设备中的键盘事件
    13.4.5    复合事件(缺少支持,用处不大)
var isSupported = document.implementation.hasFeature(‘CompositionEvent‘);
    13.4.6    变动事件
        为XML或HTML DOM设计。
  • DOM2级变动事件

变动事件触发补充
DOMSubtreeModified在DOM结构中发生任何变化时也就是说其它任何变动事件发生时都会触发
DOMNodeInstead一个节点被作为子节点插入到另一个节点 
DOMNodeRemoved将节点从父节点移除时 
DOMNodeInsertedIntoDocument节点被插入文档或通过子树间接插入文档在DOMNodeInstead 之后触发  
DOMNodeRemovedFromDocument节点从文档移除或通过子树间接移除之前在DOMNodeRemoved之后触发
DOMAttrModified特性被修改之后 
DOMCharacterDataModified文本节点的值发生变化 
  • 监测浏览器对变动事件的支持

var isSupported = document.implementation.hasFeature(‘MutationEvents‘, ‘2.0‘);
    1.    删除节点
事件(按触发先后顺序)相关属性属性值dom位置触发时机冒泡备注
DOMNodeRemovedevent.realtedNode父节点可以在DOM的任何层次处理   

使用removeChild()或replaceChild()删除节点

event.target被删除的节点 
DOMNodeRemovedFromDocument  被删除的子节点本身被移除的所有子节点会相继触发因为不会冒泡,所有必需给子节点指定事件处理程序才会触发
 
    2.    插入节点
事件(按触发先后顺序)相关属性属性值dom位置冒泡触发时机备注
DOMNodeInsertedevent.relatedNode对父节点的引用各个层次appendChild()、replaceChild()、insertBefore() 
DOMNodeInsertedIntoDocumentevent.target被插入的节点 被插入的节点 必须在插入节点前为其添加事件处理程序
DOMSubtreeModified  新插入节点的父节点   
    13.4.7    HTML5事件
    1.    contextmenu事件
触发用途冒泡屏蔽方式备注
右键单击(win);ctrl+单击(mac)如何确定显示上下文菜单或如何自定义上下文菜单DOM:event.preventDefault(); IE:event.returnValue = http://www.mamicode.com/false; 
 
EventUtil.addHandler(window, ‘load‘, function(event){    var div = document.getElementById(‘myDiv‘);    EventUtil.addHandler(div, ‘contextmenu‘, function(event){        event = EventUtil.getEvent(event);        EventUtil.preventDefault(event);        var menu = document.getElementById(‘myMenu‘);        menu.style.left = event.clientX + ‘px‘;        menu.style.top = event.clientY + ‘px‘;        menu.style.visibility = ‘‘visable;    });    EventUtil.addHandler(document, ‘click‘, function(event){        document.getElementById(‘myMenu‘).style.visibility = ‘hidden‘;    });});
    2.    beforeunload事件    :    这个事件会在浏览器卸载页面之前触发    ,可以通过它来取消卸载并继续使用原有页面。
//为了显示这个弹出的对话框,必需将event.returnValue的值设置为要显示给用户的字符串。EventUtil.addHandler(window, ‘beforeunload‘, function(event){    event = EventUtil.getEvent(event);    var message = ‘确定卸载页面吗?‘;    event.returnValue = http://www.mamicode.com/message;    return message;});
    3.    DOMContentLoaded事件    :    在形成完整的DOM树之后就会触发,不理会图像、JS文件、CSS文件或其它资源是否已经下载完毕。
  • 支持在页面下载的早期添加事件处理程序;

  • 事件会冒泡到window,但目标实际上是document;

  • event.target值为document,此外event没有额外的信息。

IE9+FirefoxChromeSafari3.1+Opera9+
//会在load事件之前触发EventUtil.addHandler(document, ‘DOMContentLoaded‘, function(event){    alert(‘Content loaded‘);});
  • 不支持DOMContentLoaded的浏览器:

//在当前JS处理完后立即运行,无法保证在所有环境下都早于load事件被触发。setTime(function(){    //在此添加事件处理程序},0);
    4.    readystatechange事件    :    提供与文档加载或元素加载状态有关的信息。
    可以很接近地模拟DOMContentLoaded事件,不能保证和load十一以相同的方式触发。
 
readyState属性值含义
uninitialized对象存在但未初始化
loading对象正在加载数据
loaded对象加载数据完毕
interactive可以操作对象了,但还没有完全加载
complete对象已经加载完毕
 
        特点:
  • 对象不一定经历所有阶段,属性变化也不总是连续的;

  • 因此readystatechange 事件经常会少于4次;

  • 与load事件一起使用时,无法预测两个事件触发的先后顺序。

EventUtil.addHandler(document, ‘readystateChange‘, function(event){    if(document.readyState == ‘interactive‘){         alert(‘Content loaded‘);    }});  
 
EventUtil.addHandler(document, ‘readystatechange‘, function(event){    if(document.readyState == ‘interactive‘ || document.readyState == ‘complete‘){        EventUtil.removeHandler(document, ‘readystatechange‘, arguments.callee);        alert(‘Content loaded‘);    }});
IEFirefox4+Opera
 
        link和script
        script
EventUtil.addHandler(window, ‘load‘, function(){    var script = document.createElement(‘script‘);    EventUtil.addHandler(script, ‘readystatecange‘, function(event){        event = EventUtil.getEvent(event);        var target = EventUtil.getTarget(event);            if(target.readyState == ‘loaded‘){            EventUtil.removeHandler(target, ‘readystatechange‘, argument.callee);        }     });    script.src = http://www.mamicode.com/‘example.js‘;    docuemnt.body.appendChild(script);});
        link
EventUtil.addHandler(window, ‘load‘, function(){    var link = document.createElement(‘link‘);    link.type = ‘text/css‘;    link.rel = ‘stylesheet‘;    EventUtil.addHandler(script, ‘readystatecange‘, function(event){        event = EventUtil.getEvent(event);        var target = EventUtil.getTarget(event);         if(target.readyState == ‘loaded‘){            EventUtil.removeHandler(target, ‘readystatechange‘, argument.callee);        }    });    link.href = http://www.mamicode.com/‘example.css‘;    docuemnt.getElementsByTagName(‘head‘)[0].appendChild(link);});
    5.    pageshow 和 pagehide事件
          往返缓存:Firefox和Opera的一个特性,这个缓存中保存着页面数据、DOM和JS状态,实际上将整个页面保存在内存里了。
          指定了onunload事件处理程序的页面会被自动排除在bfcache之外。
事件名触发目标绑定事件处理event.persisted兼容性
pageshow重新加载:load事件触发后documentwindowfalseFirefox
Safari5+
Chrome
Opera
 bfcache中的页面:页面状态完全恢复时true
pagehide浏览器卸载页面时会将该属性设为true
  • 观察pageshow事件

(function(){    var showCount = 0;    EventUtil.addHandler(window, ‘load‘, function(){        alert(‘Load fired‘);    });    EventUtil.addHandler(window, ‘pageshow‘, function(){        showCount++;        alert(‘Show has been fired ‘ + showCount + ‘ times.‘);    });})();
  • 观察pagehide事件

EventUtil.addHandler(window, ‘pagehide‘, function(event){    alert(‘Hiding.Persisted?‘ + event.persisted);});
    6.    haschange事件
触发对象属性属性值来源兼容性(属性)兼容性(事件)
URL参数列表(包括后面的所有字符串)发生变化时windowoldURL变化前的URLHTML5Firefox6+、Chrome、OperaIE8+、Firefox3.6+、Safari5+、Chrome、Opera10.6+
newURL变化后的URL
  • 捕获事件

//Firefox6+、Chrome、OperaEventUtil.addHandler(window, ‘hashchange‘, function(event){    alert(‘Old URL:‘ + event.oldURL + ‘\nNew URL:‘ + event.newURL);});//使用location对象确定当前的参数列表(考虑兼容不支持oldURL和newURL的浏览器)EventUtil.addHandler(window, ‘hashChange‘, function(event){    alert(‘Current hash:‘ + location.hash);});
  • 检测支持情况(考虑了IE8和IE7在文档模式下运行会发生BUG的问题)

var isSupported = (‘onhashchange‘ in window) &&(document.documentMode === undefined || document.documentMode > 7);
    13.4.8 设备事件
W3C从2011年开始着手指定一份关于设备事件的新草案,以涵盖不断增长的设备类型并为它们定义相关的事件。
1.    orientationchange事件    
触发相关属性支持来源 
手机屏幕横纵切换方式变化window.oritentationSafari苹果公司 
 
  • window.oritentation 

window.oritentation含义备注
0肖像模式 
90向左旋转为横向 
-90向右旋转为横向 
180头向下无设备支持

    方式一:

EventUtil.addHandler(window, ‘load‘, function(event){    var div = document.getElementById(‘myDiv‘);    div.innerHTML = ‘Current orentation is ‘ + window.orientation;    EventUtil.addHandler(window, ‘orientationchange‘, function(event){        div.innerHTML = ‘current orientation is ‘ + window.orientation;    });});
    方式二:指定<body>元素的onorientationchange特性来指定事件处理程序
    2.    MozOrientation事件
    3.    deviceorientation事件
    
    13.4.9    触摸与手势事件
 
触摸事件触发备注  
touchstart手指触摸屏幕时触发   
touchmove手指在屏幕上连续地触发   
touchend手指从屏幕上移开时   
     
 
 
 
 
 
 
 
 
 

13章 事件