• JavaScript学习笔记(十二)---- 事件


    (一)核心概念:

    事件流:事件流描述的是从页面中接收事件的顺序。IE的事件流是事件冒泡,Netscape的事件流是事件捕获流。

    在你点击按钮的同时,你也单击了按钮的容器元素,甚至也单击了整个页面。

      1) 事件冒泡:IE的事件流

      事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点。所有现代浏览器都支持事件冒泡。

    事件冒泡的过程,当单击了页面中div元素,这个click事件会按照如下顺序传播:

      2) 事件捕获:Netscape Communicator团队提出的另一种事件流

    事件捕获的用意在于在事件到达预定目标之前捕获它。

    当单击了页面中div元素,在事件捕获过程中,document对象首先接收到click事件,然后事件沿DOM树一次向下,一直传播到事件的实际目标,即<div>元素。事件捕获过程如下:

    很少使用事件捕获,可以放心地使用事件冒泡。

      3) DOM事件流

      “DOM2 级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和时间冒泡阶段。

    首先,事件捕获阶段,为截获事件提供了机会。【从外到内。从document到<html>再到<body>后就停止了。】

    然后,实际的目标接收到事件。【“处于目标”阶段,于是事件在<div>上发生,并在事件处理中被看成冒泡阶段的一部分。】

    最后,冒泡阶段,可以在这个阶段对事件作出响应。【冒泡阶段发生,事件又传播回文档。】

    单击<div>元素,顺序触发事件:

    (二).事件处理程序

    事件:就是用户或浏览器自身执行的某种动作。诸如click、load 和 mouseover,都是事件的名字。

    事件处理程序:响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以“on”开头,因此click事件的事件处理程序就是onclick,load事件的处理程序就是onload。

    为事件指定处理程序的方式:

    1)HTML事件处理程序

       某个元素支持的某种时间,都可以使用一个与相应时间处理程序同名的HTML特性来指定。

      例如:直接给onclick特性赋值,将Javascript代码作为它的值

    <input id="myButton" type="button" value="simple" onclick="alert('click!')" />

      在HTML中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本。

      例如:调用其他地方定义的脚本

    <script>
    function showHello(){
      alert("Hello");
    }
    </script>
    <input id="myButton" type="button" value="simple" onclick="showHello()" />

    指定事件处理程序具有一些独到之处。首先,这样会创建一个封装这元素属性的函数。这个函数有一个局部变量event,就是时间对象。

      输出事件类型 click

    <input id="myButton" type="button" value="simple" onclick="alert(event.type)" /> 

      直接访问时间对象,在这个函数内部,this值等于事件的目标元素。输出 simple

    <input id="myButton" type="button" value="simple" onclick="alert(this.value)" />

      扩展作用域:如果当前元素时一个表单输入元素,则作用域中还会包含访问表单元素(父元素)的入口,这个函数就变成了如下所示:

    function(){
            with(docuemnt){
                with(this.form){
                    with(this){
                        //元素属性值
                    }
                }
            }
        }

    例如:单击按钮会显示文本框中的文本,注意:这里直接引用了username元素。

    <form method="post">
        <input type="text" name="username" value="" />
        <input type="button" value="echo username" onclick="alert(username.value)" /> 
    </form>

     在HTML中指定事件处理程序的三个缺点:

      缺点一:存在时差问题。因为用户可能会在HTML元素一出现在页面上就触发相应的时间,但当时的事件处理程序有可能尚不具备执行条件。

      缺点二:扩展事件处理程序的作用域链在不同浏览器中会导致不同结果。

      缺点三:HTML与Javascript代码紧密耦合,更换事件处理程序,就要改动两个地方:HTML代码和Javascript代码。

    2)DOM0 级事件处理程序

    通过Javascript指定事件处理的传统方式,就是将一个函数赋值给一个事件处理程序属性。

    优点:一是简单,二是具有跨浏览器的优势。

    每个元素(包括window和document)都有自己的事件处理程序属性,这些属性通常全部小写,例如onclick。

    例如:给button指定click事件,

    <script>
        window.onload =function(){
            var btn = document.getElementById("myBtn");
            btn.onclick = function(){
                alert(this.id); //myBtn
            }
        }    
    </script>
    <input id="myBtn" type="button" value="echo"/> 

      删除通过DOM0 级方法指定的事件处理程序,设置事件处理程序属性的值为null即可。

    btn.onclick =null;

    3)DOM2 级事件处理程序

    "DOM2 级事件" 定义了两个方法,用于处理指定和删除事件处理程序的操作:

    addEventListener( )removeEventListener( ).所有DOM节点中都包含这两个方法

    方法接收三个参数:要处理的事件名、作为事件处理程序的函数 和 一个布尔值

    布尔值参数=true,表示在捕获阶段调用事件处理程序;

    布尔值参数=false,表示在冒泡阶段调用事件处理程序。

    例如,在按钮上为click事件添加事件处理程序:可以添加多个事件处理程序

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

    例如,删除事件处理程序

      无效的方式:

        var btn = document.getElementById("myBtn");
            btn.addEventListener("click",function(){
                alert(this.id);
            },false);        
            btn.removeEventListener("click",function(){ //这样删除无效
                alert(this.id);
            },false);

      虽然调用removeEventListener()看似使用了相同的函数,但实际上,第二个参数与传入addEventListener()中的那一个是完全不同的函数。 

     有效方式:

        <input type="button" id="myBtn" value="Click Me" />
        <input type="button" id="myRemoveBtn" value="Remove Event Handler" />
        <script type="text/javascript">
            var btn = document.getElementById("myBtn");
            var handler = function(){
                alert(this.id);
            }
            btn.addEventListener("click",handler,false);
            
            var mbtn = document.getElementById("myRemoveBtn");
            mbtn.onclick = function(){
                btn.removeEventListener("click",handler,false);
            }
        </script>

    IE9+、Firefox、Safari、Chrome 和Opera 支持DOM2 级事件处理程序。

    4)IE事件处理程序

    IE 实现了与 DOM 中类似的两个方法:attachEvent( )detachEvent( )

    接收参数事件处理程序名称事件处理程序函数

    因为IE8 及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段。

    例子:使用attachEvent() 为按钮添加一个事件处理程序,

        <input type="button" id="myBtn" value="Click Me" />
        <input type="button" id="myRemoveBtn" value="Remove Event Handler" />
        <script type="text/javascript">
            var btn = document.getElementById("myBtn");
              btn.attachEvent("onclick",function(){
                alert(this==window); //true
            });    
        </script>

      注意:attachEvent( )的第一个参数是"onclick",而非DOM的addEventListener( )方法中的“click”。

    attachEvent()与使用DOM0 级方法的主要区别在与事件处理程序的作用域:

    • 在DOM0 级方法的情况下,事件处理程序会在其所属元素的作用域中运行;
    • 在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window。

    例子:使用detachEvent( ) 删除一个事件处理程序

        <input type="button" id="myBtn" value="Click Me" />
        <input type="button" id="myRemoveBtn" value="Remove Event Handler" />
        <script type="text/javascript">
            var btn = document.getElementById("myBtn");
            var handler = function(){
                alert("Hello");
            }
              btn.attachEvent("onclick",function(){
                alert(this==window); //true
            });    
            btn.attachEvent("onclick",handler);
            
            var mbtn = document.getElementById("myRemoveBtn");
            mbtn.onclick = function(){
                btn.detachEvent("onclick",handler);
            }        
        </script>

    5)跨浏览器事件处理程序

    为了跨浏览器的方式处理事件,只要恰当地使用能力检测即可。要保证处理事件的代码在大多数浏览器下一致地运行,只需关注冒泡阶段。

    第一个要创建的方法是 addHandler( ),它的职责是视情况分别使用DOM0 级方法、DOM2 级方法 或 IE方法来添加事件。这个方法属于一个名叫 EventUtil 的对象。

    addHandler( )方法接受3个参数要操作的元素事件名称事件处理程序函数

        var EventUtil = {
                addHandler:function(element,type,handler){
                    if(element.addEventListener){    //存在DOM2级方法
                        element.addEventListener(type,handler,false);
                    }else if(element.attachEvent){    //存在的是IE方法
                        element.attachEvent("on"+type,handler);
                    }else{                             //默认采用DOM0 级方法
                        element["on"+type] = handler; //使用方括号语法来将属性名指定为事件处理程序
                    }
                },
                removeHandler:function(element,type,handler){
                    if(element.removeEventListener){
                        element.removeEventListener(type,handler,false);
                    }else if(element.detachEvent){
                        element.detachEvent("on"+type,handler);
                    }else{
                        element["on"+type]=null;
                    }
                }
            }
         var btn = document.getElementById("myBtn");
            var handler = function(){
                alert("Hello");
            }
            EventUtil.addHandler(btn,"click",handler);
            
            var mbtn = document.getElementById("myRemoveBtn");
            mbtn.onclick = function(){
                EventUtil.removeHandler(btn,"click",handler);
            }    

    (三).事件对象

    在触发DOM上的某个事件时,会产生一个事件对象event,这个对象包含着所有与时间有关的信息。

    例如:鼠标操作导致的事件对象中,会包含鼠标位置的信息。

       键盘操作导致的事件对象中,会包含与按下的键有关的信息。

    所有浏览器都支持event对象,但支持方式不同。

    1)DOM 中事件对象

    兼容DOM的浏览器会将一个event对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法(DOM0 级 或 DOM2 级),都会传入event对象。

    var btn = document.getElementById("myBtn");        
            btn.onclick = function(){
                alert(event.type);
            }
            btn.addEventListener("click",function(){
                alert(event.type);
            },false);

      在通过HTML特性指定事件处理程序时,变量event中保存着event对象。如下代码:

    <input type="button" id="htmlBtn" value="htmlBtn" onclick="alert(event.type)" />

    event 对象包含与创建它的特定时间有关的属性和方法:

      属性/方法      类型    读/写  说明

     currentTarget  Boolean    只读  其事件处理程序当前正在处理事件的那个元素

     target      Element     只读  事件的目标

     type       String      只读  被触发的事件的类型   

     cancelable    Boolean     只读  表明是否可以取消事件的默认行为

     bubbles      Boolean     只读  表明事件是否冒泡

     event       Integer      只读  调用事件处理程序的阶段:1--捕获阶段;2--处于目标;3--冒泡阶段


     preventDefault()   Function   只读  取消事件的默认行为。如果cancelable是true,则可以使用这个方法。

     stopPropagation()    Function   只读   取消事件的进一步捕获或冒泡。如果bubbles为true,则可以使用该方法

    在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标。

    var btn = document.getElementById("myBtn");        
                btn.onclick = function(event){
                    alert(event.currentTarget === this); //true
                    alert(event.target === this); //true
            }

    上面代码检测了currentTarget 和 target 与 this 的值。由于click 事件的目标是按钮,因此这三个值是相等的。

    下面的例子:事件处理程序存在于按钮的父节点中(document.body),那么这些值是不相同的。

    document.body.onclick = function(event){
                alert(event.currentTarget == document.body); //true
                alert(this == document.body); //true
                alert(event.target === document.getElementById("myBtn")); //true
            }

    当单击这个例子中的按钮时,this 和 currentTarget 都等于document.body,因为事件处理程序是注册到这个元素上的。target元素却等于按钮元素,因为它是click 事件真正的目标。由于按钮上没有注册事件处理程序,结果click事件就冒泡到了document.body,在那里才得到了处理。

    例子:在需要通过一个函数处理多个事件时,可以使用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;
    • preventDefault() 方法,阻止特定事件的默认行为

    例如,链接的默认行为就是在被单击时会导航到其href特性指定的URL。

    例子:阻止链接导航这一默认行为

    var link = document.getElementById("myLink");
            link.onclick = function(event){
                event.preventDefault();
            }
    • stopPropagation( ) 方法,用于立即停止事件在DOM层次中的传播

    例如,直接添加一个按钮的事件处理程序可以调用stopPropagation( ),从而避免触发注册在document.body上面的事件处理程序。

        var btn = document.getElementById("myBtn");
            btn.onclick = function(event){
                alert("Clicked");
                event.stopPropagation();
            };
            document.body.onclick = function(event){
                alert("Body clicked"); //不会显示
            }

    如果不调用stopPropagation(),就会在单击按钮时出现两个警告框。可是,由于click事件根本不会传播到document.body,因此就不会触发注册在这个元素上的onclick事件处理程序。 

    • event.eventPhase属性,用于确定事件当前正位于事件流的哪个阶段。

    若是在捕获阶段调用的事件处理程序 eventPhase = 1

    若事件处理程序处于目标对象上 eventPhase = 2

    若在冒泡阶段调用的事件处理程序 eventPhase = 3

    <body>
        <input type="button" value="click" id="myBtn" />
        <script type="text/javascript">
            var btn = document.getElementById("myBtn");
            btn.onclick = function(event){
                alert("btn.onclick "+event.eventPhase);   //事件处理程序处于目标对象上  2
            };    
            document.body.onclick = function(event){
                alert("body.onclick "+event.eventPhase);  //冒泡阶段调用的事件处理程序 3
            }
            document.body.addEventListener("click",function(event){
                alert("body.addEvent "+event.eventPhase);    //捕获阶段调用的事件处理程序 1
            },true);        
        </script>
    </body>

    2)IE 中事件对象

     要访问IE中的 event 对象有几种不同的方式,取决于指定事件处理程序的方法。

    • 使用 DOM0 级方法添加事件处理程序,event 对象作为window对象的一个属性存在。
    var btn = document.getElementById("myBtn");    
            btn.onclick = function(event){
                var event = window.event;
                alert(event.type); //click
            };
    • 使用DOM2 级事件处理程序,那么就会有一个event对象作为参数被传入事件处理程序函数
    var btn = document.getElementById("myBtn");    
            btn.addEventListener("click",function(event){
                alert(event.type);
            });
    • 用过HTML 特性指定的事件处理程序,仍旧可以通过一个名叫event的变量来访问event对象。
    <input type="button" value="click" id="myBtn" onclick="alert(event.type)" />

    3)跨浏览器的事件对象

    虽然DOM 和 IE 中的event对象不同,但基于它们之间的相似性依旧可以拿出跨浏览器的方案来。

    IE中event对象的全部信息和方法DOM对象中都有,只不过实现方式不一样。

    例如:增强EventUtil 对象

    var EventUtil = {
                addHandler:function(element,type,handler){
                    if(element.addEventListener){
                        element.addEventListener(type,handler,false);
                    }else if(element.attachEvent){
                        element.attachEvent("on"+type,handler);
                    }else{
                        element["on"+type] = handler;
                    }
                },
                getEvent:function(event){ //它返回对event对象的引用。
                    return event ? event:window.event;
                },
                getTarget:function(event){
                    return event.target||event.srcElement;
                },
                preventDefault:function(event){ //取消事件的默认行为
                    if(event.preventDefault){
                        event.preventDefault();
                    }else{
                        event.returnValue = false;
                    }
                },
                removeHandler:function(element,type,handler){
                    if(element.removeEventListener){
                        element.removeEventListener(type,handler,false);
                    }else if(element.dettachEvent){
                        element.detachEvent("on"+type,handler);
                    }else{
                        element["on"+type] = null;
                    }
                },
                stopPropagation:function(event){
                    if(event.stopPropagation){
                        event.stopPropagation();
                    }else{
                        event.cancelBuble=true;
                    }
                }
            }

    为EventUtil 添加了4个新方法:

    • getEvent(),它返回对event对象的引用。使用这个方法时,必须假设有一个时间对象传入到事件处理程序中,而且要把该变量传给这个方法。
    btn.onclick=function(event){
                event = EventUtil.getEvent(event);
           alert(event.type); }

    分析:在兼容DOM的浏览器中,event 变量只是简单地传入和返回。在IE中,event 参数是未定义的,因此返回window.event

    (四).事件类型

    DOM3 级事件规定了以下几类事件。

      UI(User Interface,用户界面)事件,当用户与页面上的元素交互时触发;

      焦点事件,当元素获得或是去焦点时触发。

      鼠标事件,当用户通过鼠标在页面上执行操作时触发。

      滚轮事件,当使用鼠标滚轮(或类似设备)时触发。

      文本事件,当文档中输入文本时触发。

      键盘事件,当用户通过键盘在页面上执行操作时触发。

      合成事件,当为IME(Input Method Editor,输入法编辑器) 输入字符时触发。

      变动事件,当底层DOM结构发生变化时触发。

    1)UI 事件  

      1。load 事件

      Javascript中最常用的一个事件就是load。当页面完全加载后(包括所有图像、Javascript文件、CSS文件等外部资源),就会触发window上面的load 事件。

      有两种定义onload 事件处理程序的方式:

    第一种:通过Javascript来指定事件处理程序的方式。

    EventUtil.addHandler(window,"load",function(event){
                alert("Loaded");
            })

    第二种:指定onload 事件处理程序的方式是为<body>元素添加一个onload特性。

    <body onload="alert('Loaded!')">
    </body>

    图像上面也可以触发load时间,无论是在DOM中的图像元素还是HTML中的图像元素。

      在HTML中为任何图像指定onload 事件处理程序,例如:

    <img src="c.JPG" onload="alert('Image loaded.')">

    当例子中的图像加载完毕后就会显示一个警告框。

      使用Javascript为图像加载完毕后显示一个警告框。

        EventUtil.addHandler(image,"load",function(event){
                event = EventUtil.getEvent(event);
                alert(EventUtil.getTarget(event).src); // "http://127.0.0.1:8000/Chapter01/WebContent/c.JPG"
            });

       2。unload 事件

    与load事件对应的是unload事件,这个时间在文档被完全卸载后才触发。只要用户从一个页面切换到另一个页面,就会发生unload 事件。

    用途:使用个事件的情况是清楚引用,以避免内存泄露。

      3。resize 事件

    当浏览器窗口被调整到一个新高度或宽度时,就会触发resize 事件。这个事件在window(窗口)上面触发,因此可以通过Javascript或者<body>元素中的onresize特性来指定事件处理程序。

    推荐使用Javascript方式:

    EventUtil.addHandler(window,"resize",function(event){
                alert("Resized");
            });

      4。scroll 事件

    在混杂模式下,可以通过<body>元素的scrollLeft 和 scrollTop 监控。

    在标准模式下通过<html>元素来反映。

    EventUtil.addHandler(window,"scroll",function(event){
                if(document.compatMode=="CSS1Compat"){
                    alert(document.documentElement.scrollTop);
                }else{
                    alert(document.body.scrollTop);
                }
            })

    2)焦点事件

    当焦点从页面中的一个元素移到另一个元素,会依次触发下列事件:

      focusout 在失去焦点的元素上触发。

      focusin 在获得焦点的元素上触发。

      blur 在失去焦点的元素上触发。

      DOMFocusOut 在市区焦点的元素上触发。

      focus 在获得焦点的元素上触发。

      DOMFocusIn 在获得焦点的元素上触发。

    要确定浏览器是否支持这些事件可以使用如下代码:

    var isSupported = document.implementation.hasFeature("FocusEvent","3.0");
    alert(isSupported);

    3)鼠标与滚动事件 

    鼠标事件是web开发中最常用的一类事件。DOM3 级事件中定义了9个鼠标事件。

      click:在用户单击主鼠标按钮或按下回车键时触发。

      dbclick:在用户双击主鼠标按钮时触发。

      mousedown:在用户按下任意鼠标按钮时触发。

      mouseenter:在鼠标光标从元素外部首次移动到元素范围之内时触发。不冒泡

      mouseleave:在位于元素上的鼠标光标移动到元素范围之外是触发。不冒泡

      mousemove:当鼠标指针在元素内部移动时重复地触发。

      mouseout:在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。

      mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。

      mouseup:在用户释放鼠标时触发。

      1。客户区坐标位置

    鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在 clientX 和 clientY 属性中。

    clientX、clientY:表示事件发生时鼠标指针在视口中的水平和垂直坐标。

    例子:获取鼠标事件的客户端坐标信息

    var div = document.getElementById("myDiv");
            EventUtil.addHandler(div,"click",function(event){
                event = EventUtil.getEvent(event);
                alert("Client coordinates:"+event.clientX +","+event.clientY);
            });

      这个位置并不表示鼠标在页面上的位置。

      2。页面坐标位置

    通过客户区坐标能知道鼠标时在视口中什么位置发生的,而页面坐标通过事件对象的pageX 和 pageY 属性,能告诉你事件是在页面中的什么位置发生的。

    例:取得鼠标事件在页面中的坐标

    alert("Page coordinates:"+event.pageX +","+event.pageY);

    在页面没有滚动的情况下,pageX和pageY的值与clientX和clientY的值相等。

      3。屏幕坐标位置

    鼠标事件发生时,不仅会有相对与浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置,通过screenX 和screenY 属性获得。

    alert("Screen coordinates:"+event.screenX +","+event.screenY);

      4。修改键

    在按下鼠标时键盘上的某些键的状态也可以影响到所要采取的操作。这些修改键就是Shift、Ctrl、Alt 和 Meta(在Windows键盘中是Windows键,在苹果机中是Cmd键)。

    EventUtil.addHandler(div,"click",function(event){
                event = EventUtil.getEvent(event);
                var keys = new Array();
                if(event.shiftKey){
                    keys.push("shift");
                }
                if(event.ctrlKey){
                    keys.push("ctrl");
                }
                if(event.altKey){
                    keys.push("alt");
                }
                if(event.metaKey){
                    keys.push("meta");
                }
                alert("Keys: "+keys.join(","));
            
            });

    5)键盘与文本事件 

    3个键盘事件:

      keydown : 当用户按下键盘上的任意键时触发。

      keypress :当用户按下键盘上的字符键时触发。

      keyup : 当用户释放键盘上的键时触发。

    虽然所有元素都支持以上3个事件,但只有在用户通过文本框输入文本时才最常用到。

    只有一个文本事件:

      textInput:在文本插入文本框之前会触发。

         1。键码 keyCode

    例:获取键盘上特定键的的键码

    <input type="text" id="myText"/>
    
          var text = document.getElementById("myText");
            EventUtil.addHandler(text,"keyup",function(event){
                event = EventUtil.getEvent(event);
                alert(event.keyCode);        
            });    

        2。textInput 事件

    当用户在可编辑区域中输入字符时,就会触发这个事件。

    textInput 与 keypress 的区别:

      1.任何可以获得焦点的元素都可以触发keypress事件,但只有可编辑区域才能触发 textInput事件。

      2.textInput事件只会在用户按下能够输入实际字符的键时才会被触发,而keypress事件则在按下那些能够影响文本显示的键时也会触发(例如退格键)。

    var text = document.getElementById("myText");
            EventUtil.addHandler(text,"textInput",function(event){
                event = EventUtil.getEvent(event);
                alert(event.data);        
            });

    在这个例子中,插入到文本框中的字符会通过一个警告框显示出来。

      inputMethod 属性:表示把文本输入到文本框中的方式。

     

     支持textInput 属性的浏览器有IE9+、Safari 和 Chrome。只有 IE 支持 inputMethod 属性。

     6)变动事件

    DOM2 级定义了如下变动事件

      DOMSubtreeModified : 在DOM 结构中发生任何变化时触发。

      DOMNodeInserted:在一个节点作为子节点被插入到另一个节点中时触发。

      DOMNodeRemoved:在节点从其父节点中被移除时触发。

      DOMNodeInsertedDocument: 在一个节点被直接插入文档或通过子树间接插入文档之后触发。

        DOMNodeRemovedFromDocument:在一个节点被直接从文档中移除或通过子树间接从文档中移除之前触发。这个事件在DOMNodeRemoved之后触发。

      DOMAttrModified: 在特性被修改之后触发。

      DOMCharacterDataModified:在文本节点的值发生变化时触发。

    检测浏览器是否支持变动事件: 

    var issupported = document.implementation.hasFeature("MutationEvents","2.0");

      1。删除节点

      在使用removeChild() 或 replaceChid() 从DOM中删除节点时,首先会触发DOMNodeRemoved事件。这个事件的目标(event.target)是被删除的节点,event.relatedNode属性中包含着对目标节点父节点的引用。parentNode属性仍然指向父节点。

    例:移除下面HTML页面中的<ul>元素 

    <body>
        <ul id="myList">
            <li>Item1</li>
            <li>Item2</li>
            <li>Item3</li>
        </ul>
    </body>

    分析:依次触发以下事件。

    (1)在<ul>元素上触发DOMNodeRemoved事件。relatedNode 属性等于 document.body。

    (2)在<ul>元素上触发DOMNodeRemovedFromDocument 事件。

    (3)在身为<ul>元素子节点的每个<li>元素及文本节点上触发DOMNodeRemovedFromDocument事件。

    (4)在 document.body 上触发DOMSubtreeModified 事件,因为<ul>元素是 document.body 的直接子元素。 

            EventUtil.addHandler(window,"load",function(event){
                var list = document.getElementById("myList");
                alert(list.firstChild);
                EventUtil.addHandler(document,"DOMSubtreeModified",function(event){ //2
                    alert("2-type:"+event.type);
                    alert("2-target:"+event.target);
                });
                EventUtil.addHandler(document,"DOMNodeRemoved",function(event){ //1---删除ul
                    alert("1-type:"+event.type);
                    alert("1-target:"+event.target);
                    alert("1-relatedNode:"+event.relatedNode);
                });
                EventUtil.addHandler(list.firstChild,"DOMNodeRemovedFromDocument",function(event){
                    alert("3-type:"+event.type);
                    alert("3-target:"+event.target);
                });    
                list.parentNode.removeChild(list);
            });

      2。插入节点

     在使用appendChild( )、replaceChid( ) 或 insertBefore( )向DOM中插入节点时,首先会触发DOMNodeInserted事件。这个事件的目标是被插入的节点,而event.relatedNode属性中包含一个对父节点的引用。 

            EventUtil.addHandler(window,"load",function(event){
                var list = document.getElementById("myList");
                var item = document.createElement("li");
                item.appendChild(document.createTextNode("Item4"));
                
                EventUtil.addHandler(document,"DOMSubtreeModified",function(event){
                    alert("2--"+event.type);
                    alert("2--"+event.target);
                    alert("2--"+event.relatedNode); //null
                });
                EventUtil.addHandler(document,"DOMNodeInserted",function(event){
                    alert("1--"+event.type);
                    alert("1--"+event.target);
                    alert("1--"+event.relatedNode);
                })
                EventUtil.addHandler(item,"DOMNodeInsertIntoDocument",function(event){
                    alert(event.type);
                    alert(event.target);
                });
                list.appendChild(item);
            });

     7)HTML5 事件

      1。contextmenu 事件,单击鼠标右键可以调出上下文菜单

    如何确定应该显示上下文菜单? 在Windows中,右键单击;在Mac中,Ctrl+单击

    如何屏蔽该操作关联的默认上下文菜单? contextmenu这个事件可以表示何时应该显示上下文菜单,以便开发人员取消默认的上下文菜单而提供自定义的菜单。

    contextmenu 事件是冒泡事件,这个事件的目标是发生用户操作的元素。

    在所有浏览器中都可以取消这个事件:

      在兼容DOM的浏览器中,使用event.preventDefault();

      在IE中,将event.returnValue 的值设置为false。

    contextmenu 事件属于鼠标事件,所以其事件对象中包含与光标位置有关的所有属性。通常使用contextmenu 事件来显示自定义的上下文菜单,而使用onclick事件处理程序来隐藏该菜单。

    例子:鼠标右键获取自定义的上下文菜单,单击取消该菜单。

    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 = "visible";            
            });
            EventUtil.addHandler(document,"click",function(event){
                document.getElementById("myMenu").style.visibility="hidden";
            });
        });

    (1)上下文菜单显示的位置设置,根据鼠标光标的位置决定,因此使用了clientX 和clientY

    (2)是否显示,通过style的visibility属性设置

      2。beforeunload 事件(在关闭页面之前给提醒)

    用途:为了让开发人员有可能在页面卸载前阻止这一操作。可以通过它来取消卸载并继续使用原有页面。

    这个事件的意图就是将控制权交给用户。

        EventUtil.addHandler(window,"beforeunload",function(event){
            event = EventUtil.getEvent(event);
            var message = "I'm really going to miss you if you go.";
            event.returnValue = message;
            return message;
        });

    显示效果如下:

      3。DOMContentLoaded 事件

    DOMContentLoaded 事件在形成完整的DOM树之后就会触发,不理会图像、Javascript文件、CSS文件或其他资源是否已经下载完毕。

    window 的 load 事件会在页面中的一切都加载完毕时触发,这个过程要花费一些时间。

    要处理DOMContentLoaded 事件,可以为document 或 window 添加相应的事件处理程序(尽管这个事件会冒泡到window,但它的目标实际上是document)。

       4。readystatechange 事件:提供与文档或元素的加载状态有关的信息

     IE 为DOM文档中的某些部分提供了readystatechange事件。支持readystatechange事件的每个对象都有一个readyState属性,可能包含下列5个值中的一个:

      uninitialized(未初始化):对象存在但尚未初始化。

      loading(正在加载):对象正在加载数据。

      loaded(加载完毕):对象加载数据完毕。

      interactive(交互):可以操作对象了,但还没有完全加载。

      complete(完成):对象已经加载完毕。

    并非所有对象都会经历readyState的这几个阶段。

    交互阶段可能早于也可能会晚于完成阶段出现,无法确保顺序,因此有必要同时检测交互和完成阶段。

    EventUtil.addHandler(document,"readystatechange",function(event){
                if(document.readyState=="interactive" || document.readyState=="complete"){
                    EventUtil.removeHandler(document,"readystatechange",arguments.callee);
                    alert("content loaded");
                }
            });

    对上面代码来说,当readystatechange事件触发时,会检测document.readyState的值,看当前是否已经进入交互阶段或完成阶段。如果是,就移除相应的事件处理程序以免在其他阶段再执行。注意,由于时间处理程序使用的匿名函数,因此这里使用了arguments.callee来引用该函数。

    另外,<script>和<link>元素也会触发readystatechange事件,可以用来确定外部的Javascript和CSS文件是否已经加载完成。

          EventUtil.addHandler(window,"load",function(){
                var script = document.createElement("script");    
                EventUtil.addHandler(script,"readystatechange",function(event){
                    event = EventUtil.getEvent(event);
                    var target = EventUtil.getTarget(event);
                    if(target.readyState=="interactive" || target.readyState=="complete"){
                        EventUtil.removeHandler(target,"readystatechange",arguments.callee);
                        alert("Script loaded");
                    }
                });    
                script.src="js/utils.js";
                document.body.appendChild(script);
                
                var link = document.createElement("link");
                link.type = "text/css";
                link.rel= "stylesheet";            
                EventUtil.addHandler(link,"readystatechange",function(event){
                    event = EventUtil.getEvent(event);
                    var target = EventUtil.getTarget(event);
                    if(target.readyState=="interactive" || target.readyState=="complete"){
                        EventUtil.removeHandler(target,"readystatechange",arguments.callee);
                        alert("CSS loaded");
                    }
                });
                link.href = "css/default.css";
                document.getElementsByTagName("head")[0].appendChild(link);
            });

    注意:添加link时type、rel、href属性都要添加,并且将其添加到head的子节点中

      5。pageshow 和 pagehide 事件

     "往返缓存 bfcache(back-forward cache)":可以在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度。这个缓存中不仅保存着页面数据,还保存了DOM和Javascript的状态;实际上整个页面都保存在了内存里。 

    •  pageshow 事件:在页面显示时触发,无论该页面是否来自bfcache。

     虽然这个事件的目标是 document ,但必须将其事件处理程序添加到window

      7)触摸与手势事件

       1。触摸 事件

     有以下具体几个触摸事件:

      touchstart:当手指触摸屏幕时触发

      touchmove:当手指在屏幕上滑动时连续地触发。

      touchend:当手指从屏幕上移开时触发。

      touchcancel:当系统停止跟踪触摸时触发。

    以上事件都是冒泡事件。

    在触摸屏幕上的元素时,这些事件(包括鼠标事件)发生的顺序如下:

    (1)touchstart

    (2)mouseover

    (3)mousemove

    (4)mousedown

    (5)mouseup

    (6)click

    (7)touchend

      2。手势 事件

    当两个手指触摸屏幕时就会产生手势,手势通常会改变显示项的大小,或旋转显示项。

    有三个手势事件:

      gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发。

      gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发。

      gestureend:当任何一个手指从屏幕上面移开时触发。

    @@@@@@@@@@@

    1.事件委托

    对“事件处理程序过多”问题的解决方法就是事件委托。事件委托利用是了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

    例子:分别为list添加不同的操作

        <ul id="myMenu">
            <li id="goSomewhere">Item1</li>
            <li id="doSomething">Item2</li>
            <li id="sayHi">Item3</li>
        </ul>

    传统的做法:

          var item1 = document.getElementById("goSomewhere");
            var item2 = document.getElementById("doSomething");
            var item3 = document.getElementById("sayHi");
            EventUtil.addHandler(item1,"click",function(event){
                location.href="http://www.w3cshool";
            });
            EventUtil.addHandler(item2,"click",function(event){
                document.title = "I changed the document's title";
            });
            EventUtil.addHandler(item3,"click",function(event){
                alert("Hi");
            });

    使用事件委托的做法:

         var list = document.getElementById("myMenu");
            EventUtil.addHandler(list,"click",function(event){
                event = EventUtil.getEvent(event);
                var target = EventUtil.getTarget(event);
                switch(target.id){
                    case "goSomewhere":
                        location.href="http://www.w3cshool";
                        break;
                    case "doSomething":
                        document.title = "I changed the document's title";
                        break;
                    case "sayHi":
                        alert("Hi");                
                }
            });        

    使用事件委托只为<ul>元素添加了一个onclick事件处理程序。由于所有列表项都是这个子元素的子节点,而且它们的事件都会冒泡,所以单击事件最终会被这个函数处理。事件目标是被单击的列表项,故而可以通过检测id属性来决定采取适当的操作。

     

  • 相关阅读:
    类模型NLP 学习笔记 05 (Brown Clustering && Global Linear Models)
    nullnull精美的文言文表白,一起体会吧!
    [转载]ESFramework介绍之(31)―― 消息分类及对应的处理器
    【转载】ESFramework介绍之(23)―― AgileTcp
    [转载]ESFramework 4.0 快速上手(15) -- 客户端登录验证
    【转载】ESFramework介绍之(31)―― 消息分类及对应的处理器
    【转载】ESFramework 平台下可复用的Tcp通信层实现
    【转载】ESFramework介绍之(27)-- 支持OverdueMessage (离线消息)
    高性能的大型系统经验 -- 将数据分类、并缓存
    【转载】可复用的FS
  • 原文地址:https://www.cnblogs.com/yanyangbyou/p/3973891.html
Copyright © 2020-2023  润新知