DOM Level 2 事件模型


基本事件模型〉的缺点之一,就是只能注册一个事件处理器,如果你想注册多个事件处理器,那么类似以下的方式是行不通的:

window.onload = function() {
    // 处理器一
};

window.onload = function() {
    // 处理器二
};

在上例中,第二个函数实例会成为onload参考的对象,而第一个函数实例就不再有用了。

如果想在基本事件处理中,在事件发生时处理时调用两个以上的函数,必须透过设计的方式来达到,最简单的方式之一就是…

function handler1() {
}

function handler2() {
}

window.onload = function() {
    handler1();
    handler2();
};

但通常这类设计方式不好管理。事件模型在 DOM Level 2 时获得标准化,又称为标准事件模型,DOM Level 2 事件模型允许一次注册两个以上的事件,在 Internet Explorer 9 之后,DOM Level 2 事件模型也得到比较好的支持了。

在 DOM Level 2 事件模型中,要注册事件,必须使用addEventListener方法。举个例子来说,若要以 DOM Level 2 事件模型实现〈基本事件模型〉中第一个范例,可以如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
</head>
<body>

    <button id="btn1">按钮一</button><br>
    <button id="btn2">按钮二</button><br>
    <div id="console"></div>

<script type="text/javascript">
    function handler() {
        document.getElementById('console').innerHTML 
            = `Who's clicked: ${this.id}`;
    }
    document.getElementById('btn1')
            .addEventListener('click', handler, false);
    document.getElementById('btn2')
            .addEventListener('click', handler, false);
</script>  

</body>
</html>

按我观看结果

addEventListener的第一个参数指出要注册的事件,不需要'on'开头,第二个参数是事件处理器,第三个参数为false时,表示这是个事件冒泡处理器(之后文件会再说明)。

在上例中,于事件处理器中使用this获取目前触发事件的元素,虽然目前多数遵守 DOM Level 2 的浏览器都会如此实现,不过这并不是 DOM Level 2 标准的规范,在 DOM Level 2 的标准中,可以从Event实例的currentTarget特性来获取目前触发事件的元素。

如果你使用 ES6 的箭头函数来做为事件处理器,必须特别注意的是,箭头函数的this是根据语汇环境,而不是像function根据调用者是谁来决定。

在 DOM Level 2 事件模型下,Event会作为事件处理器的第一个参数传入,有些事件有默认的动作,若要停止默认动作,在 DOM Level 2 事件模型下,必须调用EventpreventDefault方法(而不是像基本事件模型那样,从事件处理器中返回false)。例如可改写〈基本事件模型〉中第三个表单验证范例:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
</head>
<body>

  <form name="form1" action="fake.do">
      输入数据:<input name="data"><br>
      <button type="submit">送出</button>
  </form>  

<script type="text/javascript">
    document.form1.addEventListener('submit', event => {
        if(event.currentTarget.data.value.length === 0) {
            event.preventDefault();
        }
    }, false);
</script>  

</body>
</html>

按我观看结果

若要移除事件处理器,则可以使用removeEventListener,第一个参数指定事件类型,第二个参数是当初注册的函数实例,第三个参数指出要移除捕捉阶段(true)或冒泡阶段(false)的处理器,下一篇文件就会加以说明。


展开阅读全文