js 事件

javaScript 与 HTML 之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些 特定的交互瞬间。可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代 码。这种在传统软件工程中被称为观察员模式的模型,支持页面的行为(JavaScript 代码)与页面的外观(HTML 和 CSS 代码)之间的松散耦合。

1. 事件流

  事件流描述的是从页面中接收事件的顺序。

2.事件冒泡

  IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深 的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

3.事件捕获

  Netscape Communicator 团队提出的另一种事件流叫做事件捕获(event capturing)。事件捕获的思想 是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在 事件到达预定目标之前捕获它。

4.DOM事件流

  “DOM2级事件”规定的事件流包括三个阶段: 事件捕获阶段处于目标阶段 事件冒泡阶段。首 先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶 段,可以在这个阶段对事件做出响应。

5.事件绑定

(1)

<button onclick="test()">按钮</button>
function test(){
    console.log('点击事件');
}

(2)

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert("Clicked");
};
btn.onclick = null; //删除事件处理程序

(3)

“DOM2 级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener() 和 removeEventListener()。所有 DOM 节点中都包含这两个方法,并且它们都接受 3 个参数:要处 理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是 true,表示在捕获 阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序。 

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

IE 实现了与 DOM 中类似的两个方法:attachEvent()和 detachEvent()。这两个方法接受相同 的两个参数:事件处理程序名称与事件处理程序函数。由于 IE8 及更早版本只支持事件冒泡,所以通过 attachEvent()添加的事件处理程序都会被添加到冒泡阶段。

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

6.跨浏览器的事件处理程序 

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;
        }
    },
    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("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
EventUtil.removeHandler(btn, "click", handler); //移除事件

7. DOM中的事件对象

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

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

事件对象属性:

在事件处理程序内部,对象 this 始终等于 currentTarget 的值,而 target 则只包含事件的实 际目标。如果直接将事件处理程序指定给了目标元素,则 this、currentTarget 和 target 包含相同 的值。来看下面的例子。

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

要阻止特定事件的默认行为,可以使用 event.preventDefault() 方法。

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

事件对象的 eventPhase 属性可以用来确定事件当前正位于事件流的哪个阶段。

  捕获阶段 :  1

  目标阶段:2

  冒泡阶段:  3

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
    alert(event.eventPhase); //2
};
document.body.addEventListener("click", function(event){
    alert(event.eventPhase); //1
}, true);
document.body.onclick = function(event){
    alert(event.eventPhase); //3
};

ps: 只有在事件处理程序执行期间,event 对象才会存在;一旦事件处理程序执行完 成,event 对象就会被销毁。

8. IE中的事件对象

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

var btn = document.getElementById("myBtn");
    btn.onclick = function(){
        var event = window.event;
        alert(event.type);     //"click"
};

在此,我们通过 window.event 取得了 event 对象,并检测了被触发事件的类型(IE 中的 type 属性与 DOM 中的 type 属性是相同的)。可是,如果事件处理程序是使用 attachEvent()添加的,那 么就会有一个 event 对象作为参数被传入事件处理程序函数中,如下所示。

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

在像这样使用 attachEvent()的情况下,也可以通过 window 对象来访问 event 对象,就像使用 DOM0 级方法时一样。

事件对象属性:

因为事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为 this 会始终等于事件目 标。故而,最好还是使用 event.srcElement 比较保险。例如

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert(window.event.srcElement === this); //ture
};
btn.attachEvent("onclick", function(event){
    alert(event.srcElement === this); //true
});

returnValue 属性相当于 DOM 中的 preventDefault()方法,它们的作用都是取消 给定事件的默认行为。只要将 returnValue 设置为 false,就可以阻止默认行为。

相应地,cancelBubble 属性与 DOM 中的 stopPropagation()方法作用相同,都是用来停止事 件冒泡的。由于 IE 不支持事件捕获,因而只能取消事件冒泡;

stopPropagatioin() 可以同时取消事件捕获和冒泡。

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    alert("Clicked");
    window.event.cancelBubble = true; //阻止事件冒泡
};

9. 跨浏览器的事件对象

  

    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) {
            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.detachEvent){
                element.detachEvent("on" + type, handler);
            } else {
                    element["on" + type] = null;
            }
        },
        //阻止事件冒泡 捕获
        stopPropagation: function(event) {        
            if(event.stopPropagation) {  
                event.stopPropagation();   
            } else {  
                event.cancelBubble = true;        
            }    
        },
        //获取滚动条滚动的值
        getWheelDelta: function(event){
            if (event.wheelDelta){
                 return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);
            } else {
                return -event.detail * 40;
            }
        },
        //获取键盘码
        getCharCode: function(event){
            if (typeof event.charCode == "number"){
                return event.charCode;
            } else {
                return event.keyCode;
            }
        },
    }

示例:

btn.onclick = function(event){
    event = EventUtil.getEvent(event);
};

10 事件类型

(1)ui 事件: 

  • DOMActivate: 表示元素已经被用户操作激活

  • load:当页面完全加载后在 window 上面触
  • unload:当页面完全卸载后在 window 上面触发
  • abort:在用户停止下载过程时,如果嵌入的内容没有加载完,则在<object>元素上面触发
  • error:当发生 JavaScript 错误时在 window 上面触发
  • select:当用户选择文本框(<input>或<texterea>)中的一或多个字符时触发
  • resize:当窗口或框架的大小变化时在 window 或框架上面触发
  • scroll:当用户滚动带滚动条的元素中的内容时,在该元素上面触发。

 (2)焦点事件

  • blur: 在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持
  • focus: 在元素获得焦点时触发。这个事件不会冒泡;所有浏览器都支持
  • focusin:在元素获得焦点时触发。会冒泡
  • focusout:在元素失去焦点时触发

     其中,blur、和focusout的事件目标是失去焦点的元素;而focus、 focusin 的事件目标是获得焦点的元素。

(3)鼠标与滚轮事件

  • click:在用户单击主鼠标按钮(左边按钮)或者按下回车键时触发,这一点对确保 易访问性很重要,意味着 onclick 事件处理程序既可以通过键盘也可以通过鼠标执行。
  • dblclick:在用户双击主鼠标按钮(左边按钮)时触发
  • mousedown:在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件。
  • mouseenter:在鼠标光标从元素外部首次移动到元素范围之内时触发。这个事件不冒泡,而且 在光标移动到后代元素上不会触发。
  • mouseleave:在位于元素上方的鼠标光标移动到元素范围之外时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。
  • mousemove:当鼠标指针在元素内部移动时重复地触发。不能通过键盘触发这个事件。
  • mouseout:当鼠标移出目标元素上方触发,不能通过键盘触发这个事件。
  • mouseover: 鼠标移入目标元素上方,鼠标移到其后代元素上时会触发,不能通过键盘触发这个事件。
  • mouseup: 在用户释放鼠标按钮时触发,不能通过键盘触发这个事件。

  双击事件触发顺序:   

    (1) mousedown (2) mouseup (3) click (4) mousedown (5) mouseup (6) click (7) dblclick

  ie下:

    IE8 及之前版本中的实现有一个小 bug,因此在双击事件中,会跳过第二个 mousedown 和 click事件,其顺序如下:

    (1) mousedown(2) mouseup(3) click 9 (4) mouseup(5) dblclick

    IE9 修复了这个 bug,之后顺序就正确了。

(4)鼠标滚轮事件

  IE 6.0 首先实现了 mousewheel 事件。此后,Opera、Chrome 和 Safari 也都实现了这个事件。当用 户通过鼠标滚轮与页面交互、在垂直方向上滚动页面时(无论向上还是向下),就会触发 mousewheel 事件。这个事件可以在任何元素上面触发,最终会冒泡到 document(IE8)或 window(IE9、Opera、 Chrome 及 Safari)对象。与 mousewheel 事件对应的 event 对象除包含鼠标事件的所有标准信息外, 还包含一个特殊的 wheelDelta 属性。当用户向前滚动鼠标滚轮时,wheelDelta 是 120 的倍数;当用 户向后滚动鼠标滚轮时,wheelDelta 是120 的倍数

EventUtil.addHandler(document, "mousewheel", function(event){ 
  event = EventUtil.getEvent(event);
  alert(event.wheelDelta); });

Firefox 支持一个名为 DOMMouseScroll 的类似事件,也是在鼠标滚轮滚动时触发。与 mousewheel 事件一样,DOMMouseScroll 也被视为鼠标事件,因而包含与鼠标事件有关的所有属性。而有关鼠标滚 轮的信息则保存在 detail 属性中,当向前滚动鼠标滚轮时,这个属性的值是-3 的倍数,当向后滚动 鼠标滚轮时,这个属性的值是 3 的倍数。

EventUtil.addHandler(window, "DOMMouseScroll", function(event){ 
  event = EventUtil.getEvent(event);   alert(event.detail); });

(5)触摸设备

  iOS 和 Android 设备的实现非常特别,因为这些设备没有鼠标。在面向 iPhone 和 iPod 中的 Safari 开发时,要记住以下几点。

  • 不支持 dblclick 事件。双击浏览器窗口会放大画面,而且没有办法改变该行为。
  • 轻击可单击元素会触发 mousemove 事件。如果此操作会导致内容变化,将不再有其他事件发生;如果屏幕没有因此变化,那么会依次发生 mousedown、mouseup 和 click 事件。轻击不可单 击的元素不会触发任何事件。可单击的元素是指那些单击可产生默认操作的元素(如链接),或 者那些已经被指定了 onclick 事件处理程序的元素。
  • mousemove 事件也会触发 mouseover 和 mouseout 事件。
  • 两个手指放在屏幕上且页面随手指移动而滚动时会触发 mousewheel 和 scroll 事件。

(6)键盘与文本事件

  • keydown:当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件。
  • keypress: 当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件。按下 Esc 键也会触发这个事件
  • keyup:当用户释放键盘上的键时触发。
  • textInput:这个事件是对 keypress 的补充,用意是在将文本显示给用户之 前更容易拦截文本。在文本插入文本框之前会触发 textInput 事件。

  在发生 keydown 和 keyup 事件时,event 对象的 keyCode 属性中会包含一个代码,与键盘上一 个特定的键对应。

  

var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keyup", function(event){
    event = EventUtil.getEvent(event);
    alert(event.keyCode);
});

(7)HTML5 事件

  • contextmenu:右击菜单事件,可使用该事件自定义菜单
  • 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;
});

  为了显示弹出对话框,必须将 event.returnValue 的值设置为要显示给用户的字符串,同时作为函数的值返回

  • DOMContentLoaded:window 的 load 事件会在页面中的一切都加载完毕时触发,但这个过程可能会因为要 加载的外部资源过多而颇费周折。而 DOMContentLoaded 事件则在形成完整的 DOM 树之后就会触发, 不理会图像、JavaScript 文件、CSS 文件或其他资源是否已经下载完毕。与 load 事件不同, DOMContentLoaded 支持在页面下载的早期添加事件处理程序,这也就意味着用户能够尽早地与页面 进行交互。
  • hashchange :HTML5 新增了 hashchange 事件,以便在 URL 的参数列表(及 URL 中“#”号后面的所有字符串) 发生变化时通知开发人员。

 (9)触摸事件

  • touchstart:当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。

  • touchmove:当手指在屏幕上滑动时连续地触发。在这个事件发生期间,调用 preventDefault() 可以阻止滚动。
  • touchend:当手指从屏幕上移开时触发。
  • touchcancel:当系统停止跟踪触摸时触发。

  除了常见的 DOM 属性外,触摸事件还包含下列三个用于跟踪触摸的属性。

    touches:表示当前跟踪的触摸操作的 Touch 对象的数组。

    targetTouchs:特定于事件目标的 Touch 对象的数组。

    changeTouches:表示自上次触摸以来发生了什么改变的 Touch 对象的数组。

  

(10)手势事件

  • gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发。
  • gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发。
  • gestureend:当任何一个手指从屏幕上面移开时触发。

只有两个手指都触摸到事件的接收容器时才会触发这些事件。在一个元素上设置事件处理程序,意 味着两个手指必须同时位于该元素的范围之内,才能触发手势事件(这个元素就是目标)。由于这些事 件冒泡,所以将事件处理程序放在文档上也可以处理所有手势事件。此时,事件的目标就是两个手指都 位于其范围内的那个元素。

 11. 事件委托

  对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事 件处理程序,就可以管理某一类型的所有事件。例如,click 事件会一直冒泡到 document 层次。也就 是说,我们可以为整个页面指定一个 onclick 事件处理程序,而不必给每个可单击的元素分别添加事 件处理程序。

  

原文地址:https://www.cnblogs.com/bruce-gou/p/9682390.html