javascript高级程序设计读书笔记——事件总结

第13章 事件

1.1 事件冒泡

    事件开始的时候从最具体的元素接收,然后逐级向上传播到较为不具体的节点。

1.2 事件捕获

    事件捕获与冒泡相反,首先由不具体的节点接收,最后是最具体的节点接收事件。

    注意: ie的事件流是事件冒泡。由于老版本的浏览器不支持事件捕获,因此更加建议使用事件冒泡,有特殊需要的时候在使用事件捕获。

1.3 DOM事件流

    DOM2级事件规定的事件流包含三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段。首先发生事件捕获,然后是实际目标接收到时间,最后是事件冒泡阶段。


2. 事件处理程序

2.1 HTML事件处理程序

    通过HTML指定事件处理程序。

type="button" value="click me" onclick="alert('hello !')">

    HTML与事件处理函数紧密耦合,一旦改动,改动地方较多,不满足结构、样式、行为分离。

2.2 DOM0级事件处理程序

    使用js指定事件处理程序

var btn = document.getElementById("oneBtn");
btn.onclick = function() {
    alert("hello world !");
}

// 删除事件处理程序
btn.onclick = null;

    该方法简单,跨浏览器。所以至今使用仍然很广泛。

2.3 DOM2级事件处理程序

    指定了两个方法来进行添加和删除时间处理程序。addEventListener(eventType, fnname, bool ) , removeEventListener( eventType, fnname, bool )

  • eventType: 要处理的事件类型
  • fnname: 事件处理程序的函数
  • bool: true表示在捕获阶段调用事件处理函数,false表示在冒泡阶段调用。

        注意:使用DOM2级方法可以添加多个事件处理程序。通过addEventListener添加的事件监听必须使用removeEventListener来移除。

2.4 IE事件处理程序

    IE实现了与DOM中类似两个方法: attachEvent( eventType,handler )和detachEvent( eventType,handler ) 。

  • eventType: 在ie中参数是onclick而不是click。
  • handler: 事件处理函数

        注意:通过attachEvent添加的事件处理程序是在全局作用域下运行。所以 this==window。此外,attachEvent添加的多个事件处理程序触发顺序是相反的。

2.5 跨浏览器的事件处理程序

var eventUtil = {
    addHandler: function(ele, type, handler) {
        if(ele.addEventListener) {
            ele.addEventListener(type, handler, false);
        } else if(ele.attachEvent) {
            ele.attachEvent('on'+type, handler);
        } else {
            ele['on'+type] = handler;
        }
    },

    removeHandler: function(ele, type, handler) {
        if(ele.removeEventListener) {
            ele.removeEventListener(type, handler, false);
        } else if(ele.detachEvent) {
            ele.detachEvent('on'+type, handler);
        } else {
            ele['on'+type] = null;
        }
    }
}


3. 事件对象


3.1 DOM中的事件对象
    无论是DOM0级或DOM2级方法添加事件处理程序,都会传入event对象。event对象包含与创建它的特定事件的属性和方法。

属性/方法 类型 读/写 说明
bubbles Boolean 只读 表明事件是否冒泡
cancelable Boolean 只读 表明是否可以取消事件的默认行为
currentTarget Element 只读 表明事件处理程序当前正在处理的元素
defaultPervented Boolean 只读 为true表示已经调用了preventDefault()方法
detail Integer 只读 表示与事件相关的细节信息
eventPhase Integer 只读 调用事件处理程序的阶段:1表示捕获阶段,2表示目标阶段,3表示冒泡阶段
preventDefault() Function 只读 取消事件的默认行为
stopImmediatePropagation() Function 只读 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用
stopPropagation() Function 只读 阻止事件进一步捕获或冒泡
target Element 只读 目标元素
type String 只读 被触发的事件类型

    
    在事件处理程序中,对象this始终等于currentTarget,不一定等于target。

    只有在事件处理程序执行中,event对象才存在。一旦程序执行完毕,将会被立即销毁。

3.2 IE中的事件对象

属性/方法 类型 读/写 说明
cancelBubble Boolean 读写 默认为false。用于取消事件冒泡,与DOM中的stopPropagation()相同
returnValue Boolean 读写 默认为true,用于取消默认行为,与DOM中的preventDeafault()相同
srcElement Element 只读 事件目标元素,与DOM中的target相同
type String 只读 被触发的事件类型

3.3 跨浏览器的事件对象

var eventUtil = {
    addHandler: function(ele, type, handler) {
        // 代码在上文,
    },
    getEvent: function(event) {
        return event || window.event;
    },
    getTarget: function(event) {
        // 该语句可以不用,关键是传入的event是否已经被处理
        // var event = event || window.event;
        return event.target || event.srcElement;
    },
    preventDefault: function(event) {
        if(event.preventDefault) {
            event.preventDefault();
        } else { 
            event.returnValue = false;
        }
    },
    removeHandler: function(ele, type, handler) {
        // 省略代码
    },
    stopPropagation: function(event) {
        if(event.stopPropagation) {
            event.stopPropagation(();
        } else {
            event.cancelBubble = true;
        }
    },
};


4. 事件类型


4.1 UI事件

事件 说明
load 页面完全加载后触发
unload 页面完全卸载或触发
select 用户选中文本框中的文本的时候触发
resize 窗口或框架大小变化的时候触发
scroll 滚动带滚动条的内容时触发

4.2 焦点事件

    焦点事件会在页面获得或者失去焦点的时候触发。利用这些事件和 document.hasFocus()方法及document.activeElement属性配合,可以定位用户在页面上的行踪。

方法/属性 说明
blur 失去焦点时触发,不会冒泡
DOMFocusOut 失去焦点时触发,是blur的通用版本,只有opera支持,DOM废弃
focusOut 失去焦点触发,冒泡,
focus 获得焦点触发。不会冒泡
DOMFocusIn 获得焦点触发,冒泡,只要opera支持,DOM3废弃
focusIn 获得焦点触发。


    注意:判断浏览器是否支持某些事件

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

4.3 鼠标和滚轮事件

    DOM3中定义了以下9个鼠标事件

事件 说明
click 单击或回车时触发
dbclick 双击鼠标触发
mousedown 鼠标按下时触发
mouseenter 鼠标首次进入元素范围触发,且在其后代元素上不会触发
mouseleave 鼠标离开元素范围触发,与mouseenter相对
mousemove 鼠标在元素范围内移动,就会不断触发
mouseover 鼠标进入元素范围内触发,
mouseout 鼠标离开元素范围进入另一个元素范围或后代元素范围触发,


滚轮事件:mousewheel。在火狐下是DOMMouseScroll事件。

属性 说明
screenX 相对于屏幕坐标的位置
screenY 相对于屏幕位置的Y坐标
pageX 相对于页面的x坐标,ie下无pageX属性,但是有X属性。
pageY 相对于页面的y坐标,ie下无pageY属性,但是有Y属性。
clientX 相对于浏览器视口的x坐标
clientY 相对于浏览器视口位置的y坐标
function getCol(event) {
    var x = event.pageX? eventPageX: event.x;
}

修改键

属性 说明
shiftkey 检测是否按下了shift键
ctrlkey 检测是否按下了ctrl键
metakey 检测是否按下了meta键
altkey 检测是否按下了alt键


相关元素:
     mouseout以及mouseover事件中,有元素得到光标,就一定有元素失去光标。对于mouseout来说,失去光标的是主元素,得到光标的则是相关元素。mouseover则正好相反。

var eventUtil = {
    // 省略以上代码
    getRelatedTarget: function (event) {
        if(event.relatedTarget) {
            return event,relatedTarget; 
        } else if(event.toElement) {
            // for ie mouseout event
            return event.toElement;
        } else if(event.fromElement) {
            // for ie mouseover event
            return event.fromElement;
        } else {
            return null;
        }
    }
    // 省略以上代码
}

鼠标按钮
    DOM下button属性有三个值:0表示主鼠标按钮,1
表示滚轮按钮,2表示次鼠标按钮。
    在ie下,button属性的值有8个,在进行跨浏览器方法的时候,检测到时ie,则需要对button进行规范化。

var eventUtil = {
    // 省略已有代码
    getButton: function(event) {
        if(document.implementation.hasFeature("MouseEvents", "2.0")) {
            // DOM
            return event.button;
        } else {
            // ie
            switch (event.button) {
                case 0:
                case 1:
                case 3:
                case 5:
                case 7:
                    return 0;
                case 2:
                case 6:
                    return 2;
                case 4:
                    return 1;

            }
        }
    }
}

鼠标滚轮事件

    IE下: mousewheel事件,wheelDelta属性表示鼠标滚动方向,是120的倍数。向上表示+120,向下表示-120。
    FF下:DOMMouseScroll事件,detail属性。向上表示-3,向下表示+3。

var eventUtil = {
    getWheelDelta: function(event) {
        if(event.mousewheel){
            return (client.engine.opera && client.engine.opera < 9.5)? -wheelDelta:wheelDelta; 
            //在opera9.5之前,wheelDelta方向与现在相反,需要做一些处理
        } else {
            // for ff
            return -event.detail*40;
        }
    }
}

键码

var eventUtil = {
    getCharCode: function(event) {
        if(typeof event.charCode == 'number') {
            return event.charCode;
        } else {
            // IE8及以前,早期opera在keyCode中保存键码
            return event.keyCode;
        }
    }
}

textInput事件

    在DOM3级事件中引入。与keyPress不同,只有在可编辑区域内输入字符的时候触发。后者在任何可获得焦点的元素上都能触发。

4.5 复合事件

4.6 变动事件
    在DOM中的某一部分发生改变的时候给出提示。

事件 说明
DOMSubtreeModified DOM结构中发生任何变化都会被触发
DOMNodeInserted 一个节点被插入的时候触发
DOMNodeRemoved 节点被移除的时候触发
DOMNodeInsertedIntoDocument 节点被直接插入文档,或通过子树间接插入文档的时候触发。在DOMNodeInserted之后触发
DOMNodeRemovedFromDocument 节点被直接从文档中移除,或通过子树被移除的时候触发,在DOMNodeRemoved之后被触发
DOMAttrModified 在特性被修改之后触发
DOMCharacterDataModified 在文本节点的值发生变化的时候触发


注:event.relatedNode保存着相关节点。可以类比relatedTarget.

4.7 HTML5事件

5. 内存和性能

5.1 事件委托

    通过在祖先元素节点上绑定事件,每次捕获目标元素进行相应的事件处理。1. 当需要绑定的节点非常多的时候,可以采用该方法。节约内存,提升性能。 2. 对于经常动态插入节点的场景,使用事件委托,代替针对每个插入的节点进行事件绑定

    "test">
  • 1
  • 2
  • ...
  • N
// 我们不可能对N个li元素都进行事件绑定,尤其是在N很大的情况下。 // 事件委托 简单的例子 var oUl = document.getElementById('test'); eventUtil.addHandler('click', oUl, function(event) { var target = eventUtil.getTarget(event);//目标元素 // 被点击的li背景色立即变红 target.style.backgroundColor = 'red'; })

5.2 移除事件处理程序
    
    在网页中,过时不用的事件处理程序是影响性能的一个重要原因。

  1. 当直接移除带有事件处理函数的元素的时候,造成事件处理函数保持引用,无法被回收。
       在进行元素移除的时候,首先对事件处理程序进行手工移除。 例如 : btn.onclick = null;

  2. 当进行页面卸载的时候,如果在事件处理程序没有被清理干净之前卸载完成,事件处理程序就会滞留在内存中,每次加载完在卸载页面的时候,滞留的对象就会增加。
        在进行页面卸载之前,先通过onunload移除所有事件处理程序。

6. 模拟事件

6.1 DOM中的事件模拟

 通过document.createEvent()创建事件。在DOM2级中,所有事件使用英文复数,DOM3级中,使用单数。

  • UIEvents
  • MouseEvents
  • MutationEvents
  • HTMLEvents

    1. 模拟鼠标事件
// 创建事件对象
var event = document.createEvent("MouseEvents");

// 初始化事件对象
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null);

// 触发事件
btn.dispatchEvent(event);
  1. 模拟键盘事件
// DOM2级不包含键盘事件,所以使用DOM3级,在使用之前进行检查是否支持该事件
if(document.implementation.hasFeature('KeyboardEvents', '3.0')) {
    var event = document.createEvent('KeyboardEvents');

    // 初始化事件
    event.initKeyboardEvent('keydown', true, true, document.defaultView, 'a', 0, 'Shift', 0);

    // 触发事件
    textbox.dispatchEvent(event);
}

// 以上模仿的是,按下A同时按下shift键。

    注: 以上代码虽然能够模拟键盘事件的触发,却无法向文本域输入任何字符。这是因为无法精确模拟键盘事件

  1. IE中的事件模拟
       
var event = document.createEventObject(); // 不接收参数

// 初始化事件对象,必须手工添加属性
event.altKey = false;
event.ctrlKey = false;
event.keyCode = 65;
// 对添加的属性没有任何限制,即使添加的属性不支持也不所谓。

// 触发事件
textbox.fireEvent('onkeypress', event)

你可能感兴趣的:(javascript高级程序设计读书笔记——事件总结)