事件

一、事件流

:从页面中接收事件的顺序
JS和HTML之间的交互是通过事件实现的

1. IE: 事件冒泡流

具体的元素逐级向上传播到不具体的节点
所有现代浏览器都支持事件冒泡
如:

<!DOCTYPE html>
<html>
  <head>
    <body>
      <div id="myDiv"> Click me </div>
    </body>
  </head>
</html>

<div>--<body>--<html>-document对象

PS: 每个载入浏览器的 HTML 文档都会成为 Document 对象。
Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。
Document 对象是 Window 对象的一部分,可通过 window.document 属性对其进行访问。

2. Netscape Communicator: 事件捕获流

document--<html>--<body>--<div>
很少使用事件捕获

3.DOM事件流

DOM2级:
事件捕获阶段 | 处于目标阶段 | 事件冒泡阶段
document--<html>--<body> | --<div>-- |<body>--<html>-document对象
实际目标(div元素)在捕获阶段不会接收到事件

二、事件处理程序

1.HTML事件处理程序

<input onclick="">
  • 事件处理程序中的代码在执行是有权访问全局作用域中的任何代码
    “HTML标签的on-属性”
  • 优点:
  • 简单
    具有跨浏览器的优势
  • 缺点:
    同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次。
    时差问题: 用户可能会HTML元素一出现就在在页面上触发相应的时间,但当时的事件处理程序可能还没有执行条件。因此,会封装其在一个try-catch块中。
<input type="button" value="click me" onclick="try{showMessage();} catch(ex){}">

扩展事件处理程序的作用域链在不同浏览器中会导致不同结果。
HTML和JS代码紧密耦合(若要更换,要改两个地方)

2.DOM0级事件处理程序

每个元素都有自己的事件处理程序属性

var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("clicked");
alert("this.id"); // "myBtn"
}

若这些代码在页面中位于按钮后面,有可能在一段时间内怎么单击都无反应。
事件处理程序在元素的作用域中运行,this引用当前元素。
删除事件处理程序

btn.click = null;

3.DOM2级事件处理程序

指定: addEventListener()
删除:removeEventListener()
三个参数: 处理的事件名、作为事件处理程序的函数、布尔值(true-捕获,false-冒泡阶段调用事件处理程序-大多数)

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

移除时间是要参数相同。匿名函数无法移除。

  • 如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除(不必使用removeEventListener方法手动去除)。
function hello() {
  console.log('Hello world');
}

document.addEventListener('click', hello, false);
document.addEventListener('click', hello, false);

//执行上面代码,点击文档只会输出一行Hello world。
  • 如果希望向监听函数传递参数,可以用匿名函数包装一下监听函数。
function print(x) {
  console.log(x);
}

var el = document.getElementById('div1');
el.addEventListener('click', function () { print('Hello'); }, false);

//上面代码通过匿名函数,向监听函数print传递了一个参数。

4.IE事件处理程序

添加: attachEvent()
移除: detachEvent()
参数:第一个参数要加on,onclick
在 IE中使用attachEvent与使用DOM0级方法主要区别:
事件处理程序的作用域
attachEvent: 全局作用域, this===window
DOM0级:所属元素的作用域

var btn=document.getElementById("myBtn");
btn.attachEvent("click", function(){
  alert(this.id);
}, false);
btn.attachEventr("click", function(){
  alert("hello world");
}, false); 
//hello world
//myBtn
反序触发

detachEvent: 相同参数,匿名函数不能移除

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

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;
        }
    }
}
//DOM2/IE/DOM0(现代浏览器应该不会到DOM0这一步)

三、事件对象 event

1.DOM中的事件对象

兼容DOM的浏览器会将一个event对象传入到事件处理程序中
bubbles :是否冒泡
cancelable :是否可取消默认行为
currentTarget :正在处理时间的元素
detail : 与事件相关的细节信息
eventPhase :1捕获,2处于目标,3冒泡
preventDefault() :取消事件默认行为(cancelable为true)
stopPropagation():取消事件进一步捕获或冒泡(bubbles为true)
target:事件的目标
type:被触发事件的类型

  • 直接将事件处理程序指定给目标元素,click事件的目标是按钮
var btn = document.getElementById("myBtn");
        btn.onclick = function(event){
            alert(event.currentTarget === this);//true
            alert(event.target === this);//true
        };        

currentTarget===target===this
若位于按钮的父节点,值不同

document.body.onclick = function(event){
            alert(event.currentTarget === document.body);   //true
            alert(this === document.body);                  //true
            alert(event.target === document.getElementById("myBtn")); //true
        };       
  • 通过一个函数处理多个事件,用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;

2.IE中的事件对象

event对象作为window对象的一个属性存在
cancelBubble :默认false,true时可取消事件冒泡(相当于stopPropagation())
returnValue:false时取消默认行为(preventDefault())
srcElement:事件目标(target)
type:被触发事件的类型

3.跨浏览器的时间对象

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;
    },
    
    getWheelDelta: function(event){
        if (event.wheelDelta){
            return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);
        } else {
            return -event.detail * 40;
        }
    },
    
    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;
        }
    }

};

4.内存与性能

添加到页面上的事件处理程序数量直接关系到整个页面的整体运行性能:
每个函数都是对象,会占用内存,性能差
事先指定的所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪事件

  • 事件委托
    利用事件冒泡,指定一件,管理一类事件
    如:给ul里每个li用click
<ul id="myLinks">
        <li id="goSomewhere">Go somewhere</li>
        <li id="doSomething">Do something</li>
        <li id="sayHi">Say hi</li>
    </ul>
 var list = document.getElementById("myLinks");
        
        EventUtil.addHandler(list, "click", function(event){
            event = EventUtil.getEvent(event);
            var target = EventUtil.getTarget(event);
        
            switch(target.id){
                case "doSomething":
                    document.title = "I changed the document's title";
                    break;
        
                case "goSomewhere":
                    location.href = "http://www.wrox.com";
                    break;
        
                case "sayHi":
                    alert("hi");
                    break;
            }
        });

    })();

使用事件委托,只需在DOM树中尽量最高的层次上添加一个事件处理程序

  • 移除事件处理程序
    移除过时不用的事件处理程序,提高性能
    removeChild(), replaceChild()方法,若带有事件处理程序的元素被innerHTML删除了,则原来可能无妨被当做垃圾回收。
    只能手工移除: btn.onclick = null;
    事件处理程序中,删除按钮也能阻止事件冒泡

如事先指定会用innerHTML替换页面中一部分,则可不直接将事件处理程序添加到该部分元素中,而通过指定给较高层元素,同样能处理该区域中的事件。

  • 空事件处理程序另一种情况:卸载页面时,卸载前没清除干净,滞留在内存中。
    只要通过onload事件处理程序添加的东西,最后要通过onunload事件处理程序将它们移除。

5.事件类型

  • UI事件
    load事件
    unload
    resize
    scroll
  • 焦点事件
    blur
    DOMFocusIn
    DOMFocusOut
    focus
    focusin
    focusout
  • 鼠标与滚轮事件
    click
    dbclick
    mousedown
    mouseenter
    mouseleave
    mousemove
    mouseout
    mouseover
    mouseup
    客户区坐标位置
    页面坐标位置
    屏幕坐标位置
    修改键
    相关元素
    鼠标按钮
    更多时间信息(detail属性)
    鼠标滚轮事件
    触摸设备
  • 键盘与文本事件
    keydown
    keypress
    keyup
    键码
    字符编码
    DOM3级变化
    textInput事件
    设备中的键盘事件
  • 复合事件
    compositionstart
    compositionupdate
    compositionend
  • 变动事件
    DomSubtreeModified
    DomNodeInserted
    DomNodeRemoved
    删除节点
    插入节点
  • HTML5事件
    contextmenu事件
    beforeunload事件
    DOMContentLoaded事件
    readystatechange事件
    pageshow和pagehide事件
    haschange事件
  • 设备事件
    orientationchange
    MozOrientation
    deviceorientation
    devicemotion
  • 触摸与手势事件

6.模拟事件

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,137评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,824评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,465评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,131评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,140评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,895评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,535评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,435评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,952评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,081评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,210评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,896评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,552评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,089评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,198评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,531评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,209评论 2 357

推荐阅读更多精彩内容

  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,498评论 1 11
  • JavaScript 程序采用了异步事件驱动编程模型。在这种程序设计风格下,当文档、浏览器、元素或与之相关的对象发...
    劼哥stone阅读 1,257评论 3 11
  • JavaScript 与 HTML 之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬...
    threetowns阅读 346评论 0 0
  • js之事件机制 1、事件初探 1.1 js事件的概述 JavaScript事件:JavaScript是基于事件驱动...
    道无虚阅读 2,371评论 1 3
  • 一、学习与思考 1.今天我学到了哪些东西? 。“心流体验”。 。“痛苦只是一个标签”。 2.今天我有哪些启发和思考...
    小鱼爱笑阅读 217评论 0 1