首页 > 代码库 > 事件处理

事件处理

1.  focusblur事件不会冒泡。

2.  keydownkeyup事件是低级键盘事件,无论何时按下或释放按键(甚至是辅助键)都会触发他们。当keydown事件产生可打印字符时,在keydownkeyup事件之间会产生很多keypress事件。keypress是较高级的文本事件,其事件对象指定产生的字符而非按下的键。

3.  注册事件两种方法:1)出现在Web初期,给事件目标对象或文档元素设置属性。2)这种方式更新并更通用,是将事件处理程序传递给对象或元素的一个方法,如addEventListener()。

4.  事件处理程序的名字由”on”后跟着事件名组成:onclickonchangeonloadonmouseover等。注意这些属性名是区分大小写的,所有都是小写,即使事件类型由多个词组成(比如“readychange”)。

5.  注册和删除事件:addEventListenerremoveEventListener,然而IE9之前不支持这两个方法,IE5之后版本定义了类似的attachEvent()和detachEvent()与前面两个函数的不同之处有:

    1)  因为IE事件模型不支持事件捕获,所以attachEvent()和detachEvent()要求只有两个参数:事件类型和处理程序函数

    2)  IE方法的第一个参数使用了带“on”前缀的事件处理程序属性名而非没有前缀的事件类型。例如每当addEventListener()传递click时,attachEvent()传递“onclick

    3)  attachEvent()允许相同的事件处理程序函数注册多次。当特定的事件类型发生时,注册函数的调用次数和注册次数一样

6.  在事件处理程序内,this关键字指的是事件目标,当使用addEventListener()注册时,调用的处理程序使用事件目标作为它们的this值。但是,对于attachEvent()注册的处理程序作为函数,它们的this值是全局(window)对象。可用如下代码解决问题:

/*

在指定的事件目标上注册用于处理指定类型事件的指定处理程序函数

确保处理程序一直作为事件目标的方法调用

 */

functionaddEvent(target,type,handler){

    if(target.addEventListener){

        target.addEventListener(type,handler,false);

    }else{

       target.attachEvent("on"+type,function(event){

            //把处理程序作为事件目标的方法调用

            //传递事件对象

            return handler.call(target,event);

        });

    }

}

注意:使用这个方法注册的事件处理程序不能删除,因为传递给attachEvent()的包装函数没有保存下来传递给detachEvent()。

7.  事件处理程序的作用域:它们在其定义时的作用域而非调用时的作用域中执行,并且它们能存取那个作用域中的任何一个本地变量。但是通过HTML属性来注册事件处理程序是一个例外,它们被转换为能存取全局变量的顶级函数而非任何本地变量。但是由于历史原因,它们运行在一个修改后的作用域链中,通过HTML属性定义的事件处理程序能好像本地变量一样使用目标对象,容器<form>对象(如果有)和Document对象的属性。HTML属性最不自然的地方包括冗长的代码串和修改会的作用域链允许有用的快捷方式,可以使用tagName替代this.tagName,使用getElementById()替代document.getElementById()。并且,对于<form>中的文档元素,能通过ID引用任何其他的表单元素,例如zicode替代this.form.zipcode。另一方面,HTML事件处理程序中修改的作用域链是陷阱之源,因为作用域链中每个对象的属性在全局对象中都有相同名字的属性。例如Document对象定义(很少使用)open()方法,因此HTML事件处理程序想调用Window对象的open方法就必须显示地调用window.open而不是open。表单有类似的问题但破坏性更大,因为表达元素的名字和ID在包含的表单元素上定义属性。例如表单包含一个ID是“location”的元素,那么要是表单的所有HTML事件处理程序想引用windowlocation对象,就必须使用window.location而不能是location

8.  事件的调用顺序:1)通过设置对象属性或HTML属性注册的处理程序一直优先调用。2)使用addEventListener()注册的处理程序按照它们的注册顺序调用。3)使用attachEvent()注册的处理程序可能按照任何顺序调用,所以代码不应该依赖于调用顺序。

9.  文档元素上的load事件会冒泡,但它会在Document对象上停止冒泡而不会传播到WIndow对象。

10.             事件取消:在支持addEventListener()的浏览器中,也能通过调用事件对象的preventDefault()方法取消事件的默认操作。不过,在IE9之前的IE中,可以通过设置事件对象的returnValue属性为false来达到同样的效果。下面用全部三种技术:

function cancelHandler(event){

    varevent=event||window.event;

    /*这里是处理事件的代码*/

    if(event.preventDefault){

        event.preventDefault();//标准技术

    }else if(event.returnValue){

        event.returnValue=http://www.mamicode.com/false;

    }

    return false;

}

11.             提供一个当文档准备就绪时(图片没有加载完,可以和图片加载并行运行)的函数。当文档为操作准备就绪时,传递给whenReady()的函数将会作为Document对象的方法调用。whenReady监听DOMContentLoadedreadystatechange事件,而是用load事件仅仅是为了兼容那些不支持之前事件的较老浏览器。

/*

传递函数给whenReady(),当文档解析完毕且为操作准备就绪时,

函数将作为文档对象的方法调用

DOMContentLoadedreadystatechangeload事件发生时,会触发注册函数

一旦文档准备就绪,所有函数将被调用,任何传递给whenReady()的函数都将立即调用

*/

var whenReady=(function(){

    var funs=[];//当获得事件时,要运行的函数

    var ready=false;

    //当文档准备就绪时,调用事件处理程序

    function handler(e){

        if(ready){

            return;//如果已经运行过一次,只需返回

        }

        //如果发生readystatechange事件

        //但其状态不是“complete”的话,那么文档尚未准备好

       if(e.type==="readystatechange"&&document.readyState!=="complete"){

            return;

        }

        //运行所有注册函数

        //注意每次都要计算funcs.length,

        //以防这些函数的调用可能会导致更多的函数

        for(var i=0;i<funcs.length;i++){

            funcs[i].call(document);

        }

        //现在设置ready标识为true,并移除所有函数

        ready=true;

        funcs=null;

    }

        //为接收到的任何事件注册处理程序

        if(document.addEventListener){

           document.addEventListener("DOMContentLoaded",handler,false);

           document.addEventListener("readystatechange",handler,false);

           window.addEventListener("load",handler,false);

        }else if(document.attachEvent){

           document.attachEvent("onreadystatechange",handler);

            window.attachEvent("onload",handler);

        }

        return function whenReady(f){

            if(ready){//若准备完毕,只需运行它

                f.call(document);//否则,加入队列等候

            }

        }

}());

12.除“mouseenter”和“mouseleave”外的所有鼠标事件都能冒泡。

13.传递给鼠标事件处理程序的事件对象有clientXclientY属性,它们指定了鼠标指针相对于包含窗口的坐标。加入窗口的滚动偏移量就可以把鼠标位置转换成文档坐标。

14.altKeyctrKeymetaKeyshiftKey属性指定了当事件发生时是否有各种键盘辅助功能键按下。

15.大多数浏览器中,事件对象的keyCode属性指定了输入字符的编码。但是由于历史原因,FIrefox使用的是charCode属性。大多数浏览器只在当产生可打印字符时触发keypress事件。但firefox在产生非打印字符时也触发keypress事件。为了检测这种情况(这样就能忽略非打印字符),可以查找有charCode属性但值为0的事件对象。以下提供一个文本框过滤函数。

/*

html代码:<inputid="zip" type="text"data-allowed-chars="0123456789" data-messageid="zipwarn">

<spanid="zipwarn" style="color:red;visibility:hidden;">只支持数字</span>

这个模块相当不唐突,它没有定义全局命名空间中的任何符号

*/

whenReady(function(){

    varinputelts=document.getElementsByTagName("input");

    for(var i=0;i<inputelts.length;i++){

        var elt=inputelts[i];

        //如果不是文本域,或者没有data-allowed-cahrs属性的元素,则跳过

       if(elt.type!="text"||!elt.getAttribute("data-allowed-cahrs")){

            continue;

        }

        //input元素上注册事件处理程序函数

        //传统的keypress事件处理程序能够在任何地方运行

        //textInput(混合大小写)2010年后SafariChrome支持

        //textinput(小写)是3DOM事件规范草案中的版本

        if(elt.addEventListener){

            elt.addEventListener("keypress",filter,false);

           elt.addEventListener("textInput",filter,false);

           elt.addEventListener("textinput",filter,false);

        }else{

           elt.attachEvent("onkeypress",filter);

        }

    }

    //这是用于过滤用户输入的keypresstextInputtextinput事件处理程序

    function filter(event){

        //获取事件对象和目标元素对象

        var e=event||window.event;//标准或IE模型

        var target=e.target||e.srcElement;//标准或IE模型

        var text=null;

        //获取输入的字符或文本

        if(e.type==="textinput"||e.type==="textInput"){

            text=e.data;

        }else{//这是传统的keypress事件

            //对于可打印键的keypress事件,FireFox使用charcode

            var code=e.charCode||e.keyCode;

            //如果按下的是任何形式的功能键,不要过滤它

            if(code<32||   //ASCII控制字符

            e.charCode==0||  //功能键(仅指Firefox)

            e.ctrKey||e.altKey){//按下辅助功能键

                return;

            }

            text=String.fromCharCode(code);

        }

        //现在需要从input元素中寻找所需信息

        var allowed=target.getAttribute("data-allowed-cahrs");

        varmessageid=target.getAttribute("data-messageid");

        if(messageid){

            varmessageElement=document.getElementById(messageid);

        }

        //遍历输入文本中的字符

        for(var i=0;i<text.length;i++){

            var c=text.charAt(i);

            if(allowed.indexOf(c)==-1){//不允许的字符

                if(messageElement){

                   messageElement.style.visibility="visible";

                }

                //取消默认行为

                if(e.preventDefault){

                    e.preventDefault();

                }

                if(e.returnValue){

                    e.returnValue=http://www.mamicode.com/false;

                }

                return false;

            }

        }

        if(messageElement){

            messageElement.style.visibility="hidden";

        }

    }

});

keypress事件和textinput事件是在新输入的文本真正插入到聚焦的文档元素前触发,这就是这些事件处理程序能够取消事件和阻止文本插入的原因。浏览器也实现了在文本插入到元素后才触发的input事件类型input。虽然这些事情不能取消,不能指定其事件对象中的最新文本,但它们能以某种形式提供元素文本内容发生改变的通知。HTML5标准化了input事件,除了IE外的所有浏览器都支持它。在IE中使用不标准的propertychange事件监测文本输入元素的value属性改变来实现相似的效果。下面提供一个兼容性的方法:

functionforceToUpperCase(element){

    if(typeof element=="string"){

       element=document.getElementById(element);

    }

    element.oninput=upcase;

    element.onpropertychange=upcaseOnPropertyChange;

    function upcase(event){

        this.value=http://www.mamicode.com/this.value.toUpperCase();

    }

    function upcaseOnPropertyChange(event){//兼容IE

        var e=event||window.event;

       if(e.propertyName==="value"){//value属性发生变化

            //移除onpropertychange处理程序,避免循环调用

            this.onpropertychange=null;

            //把值变成大写

           this.value=http://www.mamicode.com/this.value.toUpperCase();

            //然后恢复propertychange处理程序

           this.propertychange=upcaseOnPropertyChange;

        }

    }

}


本文出自 “虎哥的博客” 博客,请务必保留此出处http://7613577.blog.51cto.com/7603577/1581779

事件处理