愿你坚持不懈,努力进步,进阶成自己理想的人

—— 2017.09, 写给3年后的自己

Javascript学习总结——事件处理机制

一、绑定事件

1、我们可以 通过HTML元素的属性绑定事件,这些事件属性通常是on开头,紧接着事件名称的属性名。如onsubmitonclickondblclick等,属性值则表示事件发生时,需要执行的语句(多条语句之间用;分隔),如:<form onsubmit="return check(this)">;当在元素属性中绑定事件,this指向的是HTML元素本身

该方法简单易用,但是由于和HTML元素紧密联系,不能比较好地实现分离

2、通过获取DOM对象,为DOM对象的属性绑定一个事件处理器,实现事件绑定
1)我们首选需要获取一个对象,如var form = document.forms[0]
2)然后,改变这个DOM对象的事件属性,绑定一个事件处理器,如:

form.onsubmit = function() {
    // 事件处理内容
}

常用的事件有:

  • onabort,图片加载被中断;onerror图片加载出错,适用于img标签
  • onblur,失去焦点;onfocus得到焦点,适用于button、input、label、select、textarea、body标签
  • onchange,表单域的值被改变,适用于input、select、textarea
  • onclick,点击时事件;ondblclick,双击时事件,适用于大部分标签
  • onkeydownonkeypress,在按下键盘的某个键后触发,两者的区别在于,第一次按下键后,触发keydown,如果按键没有改变,就触发keypress;当用户释放键的时候,触发onkeyup
  • onmousedown,按下鼠标时触发,onmouseup,放开鼠标时触发,onclick包含了这一个过程
  • onmouseover,鼠标进入悬停时触发,onmouseout,鼠标悬停离开时候触发
  • onmousemove,鼠标在区域上移动时触发
  • onreset,重置表单时候触发;onresize,窗口大小改变时触发
  • onsubmit,提交时候触发;onselect,当用户选择文本框或文本域的某段文字时触发

3、HTML元素一般都有一些默认行为,比如<a>标签的默认行为是跳转,表单<button type="submit"> 的默认行为是提交表单,我们可以通过返回值返回true或者false,来控制这一默认行为(正常进行或者阻止)

4、IE中的特殊事件绑定机制
1)script for绑定:通过<script>标签中加入for和event属性进行事件的绑定,for的属性值为元素ID,event的属性值为事件名称,如:

<a href="javascript:;" id="link">Click</a>
<script for="link" event="onclick" type="text/javascript">
    alert("Hello!");
</script>

2)使用DOMObject.attachEvent(eventName, functionReference)进行事件绑定,如:

document.getElementById('link').attachEvent("onclick", showHello);

3)使用DOMObject.detachEvent(eventName, functioReference)取消事件绑定



4)使用DOMObject.fireEvent(eventName, event)来重定向事件,把当前对象传播到另一个DOM节点上
5)使用target.setCaptrue()捕获鼠标事件,使用target.releaseCaptrue()释放捕获

二、访问事件对象

事件对象封装了事件发生时的详细信息,当事件发生的时候,浏览器会创建一个隐式可用的事件对象,通过event就可以访问该对象

event对象有如下的常用属性:

  • type 事件名称(如click)
  • srcElement 发生事件的HTML元素
  • clientX / clientY 鼠标事件发生位置的在页面中的坐标
  • offsetX / offsetY 鼠标事件发生时相对于事件源的坐标
  • button 鼠标事件发生时,所用的鼠标键
  • keyCode 键盘中按下的键的ASCII码
  • key 键盘中按下键的名称
  • altKey、ctrlKey、shiftKey,返回boolean值,用于表明是否按下alt、ctrl、shift键
  • cancelBubble 阻止事件冒泡
  • returnValue 返回事件处理函数的返回值,返回false的时候,默认行为被取消
  • fromElement 对mouseovermouseout事件有效,返回移出的HTML元素,toElement则是返回移入的HTML元素


三、在代码中触发事件

我们可以通过JS来模拟用户事件行为,其主要通过两个步骤:
1)获取DOM对象
2)执行DOM对象中的事件方法,如:click()blur()focus()select()submit()reset()


四、事件冒泡

1、在事件机制中,有冒泡事件非冒泡事件(如:表单提交、获得焦点),对于一个典型的冒泡事件如

<div onclick="console.log(1)">
    <div onclick="console.log(2)">
        <div onclick="console.log(3)">
            <div onclick="console.log(4)">
                <a href="javascript:;" onclick="console.log(5)">Hello</a>
            </div>
        </div>
    </div>
</div>

当点击“Hello”后,运行结果将是5 4 3 2 1
2、所谓事件冒泡,就是当一个节点的事件发生的时候,会沿着着它的父节点传播(从下到上),然后如果父节点中定义有同样的事件,就会触发父节点中的事件
3、并不是每个事件都支持冒泡,比如abortblurerrorfocusloadmouseentermouseleaveresizeunload以及H5定义的一些新事件(参考自SegmentFault)都不会冒泡:

media相关事件,都不冒泡
History相关事件:pagetransition不冒泡

4、如果要阻止冒泡,可以修改event.cancelBubble属性为true


五、DOM的事件模型

这种模型是由标准指定的,Firefox、chrome、opera等浏览器都支持该种事件模型,一般进行JS事件编程的时候,需要同时考虑IE模型和DOM模型(行业规范)

1、绑定事件,采用objectTarget.addEventListener("eventType", handler, captueFlag)。和IE的attachEvent不同的是,IE中指定事件类型需要加“on”,而addEventListener不用加“on”;第二个参数指定事件处理函数,第三个参数则指定监听事件传播的哪个阶段(true表示监听捕获阶段,false表示监听冒泡阶段)
2、事件捕获与事件冒泡的区别,首先,测试以下代码:

<div id="test">
    <input type="button" id="btn" value="Click" />
</div>

<script type="text/javascript">
function handler1(event) {
    console.log("捕获方式:");
    console.log(String(event.currentTarget));
}

function handler2(event) {
    console.log("冒泡方式:");
    console.log(String(event.currentTarget));
}

var test = document.getElementById('test');
var btn  = document.getElementById('btn');

test.addEventListener("click", handler1, true);
btn.addEventListener("click", handler1, true);

test.addEventListener("click", handler2, false);
btn.addEventListener("click", handler2, false);
</script>

当我们点击“Click”按钮的时候,将输出:

捕获方式:
[object HTMLDivElement]
捕获方式:
[object HTMLInputElement]
冒泡方式:
[object HTMLInputElement]
冒泡方式:
[object HTMLDivElement]

因此,可以看出,捕获和冒泡的区别在于(以下的指的是事件源):

  • 捕获是由外向内传播
  • 冒泡是由内向外传播

3、删除事件,使用objectTarget.removeEventListener("eventType", handler, captrueFlag)
4、访问事件对象:和IE模型不同的是,DOM模型会将事件对象作为事件处理函数的第一个参数传入,如:

var btn  = document.getElementById('btn');
btn.onclick = function(e) {
    console.log(e);
}

5、可以使用event.preventDefault()来取消事件的默认行为


六️、事件传播

1、事件传播示意图:
-----------------------------------------------------> 事件捕获阶段
[顶层DOM对象] [父DOM对象] [子DOM对象] [孙DOM对象]
<----------------------------------------------------- 事件冒泡阶段
2、事件捕获是由外及内的,而事件冒泡则是由内及外的,而且捕获阶段发生得比冒泡阶段要来得早。如果要阻止事件的传播过程,则可以用event.stopPropagation()阻止事件传播,示例如下:

<div id="test">
    <input type="button" id="btn" value="Click" />
</div>

<script type="text/javascript">
function handler1(event) {
    event.stopPropagation();
    console.log("捕获方式:" + event.currentTarget);
}

function handler2(event) {
    event.stopPropagation();
    console.log("冒泡方式:" + event.currentTarget);
}

var test = document.getElementById('test');
var btn  = document.getElementById('btn');

test.addEventListener("click", handler2, false);
btn.addEventListener("click", handler2, false);

test.addEventListener("click", handler1, true);
btn.addEventListener("click", handler1, true);
</script>

运行后,可以发现,输出结果为:捕获方式:[object HTMLDivElement]
分析一下,可以知道:

  • 因为事件传播是从捕获先开始,所以div#test的事件会先得到处理,事件函数中执行了event.stopPropagation()导致传播停止,所以就只有div#test的事件得到处理,故输出捕获方式:[object HTMLDivElement]
  • 如果把事件捕获的代码注释掉,我们可以发现输出的结果为冒泡方式:[object HTMLInputElement],说明冒泡方式是从内向外传播的,但是因为执行了阻止冒泡,因而冒泡阶段,div#test上的事件函数不会得到执行