DOM事宜机制

媒介

本文重要引见DOM事宜级别、DOM事宜模子、事宜流、事宜代办和Event对象罕见的运用,愿望对你们有些协助和启示!

本文首发地点为GitHub博客,写文章不容易,请多多支撑与关注!
《DOM事宜机制》

一、DOM事宜级别

DOM级别一共能够分为四个级别:DOM0级、DOM1级、DOM2级和DOM3级。而DOM事宜分为3个级别:DOM 0级事宜处置惩罚,DOM 2级事宜处置惩罚和DOM 3级事宜处置惩罚。由于DOM 1级中没有事宜的相关内容,所以没有DOM 1级事宜。

1.DOM 0级事宜

el.onclick=function(){}

// 例1
var btn = document.getElementById('btn');
 btn.onclick = function(){
     alert(this.innerHTML);
 }

当愿望为同一个元素/标签绑定多个同范例事宜的时刻(如给上面的这个btn元素绑定3个点击事宜),是不被许可的。DOM0事宜绑定,给元素的事宜行动绑定要领,这些要领都是在当前元素事宜行动的冒泡阶段(或许目的阶段)实行的

2.DOM 2级事宜

el.addEventListener(event-name, callback, useCapture)

  • event-name: 事宜称号,能够是规范的DOM事宜
  • callback: 回调函数,当事宜触发时,函数会被注入一个参数为当前的事宜对象 event
  • useCapture: 默许是false,代表事宜句柄在冒泡阶段实行
// 例2
var btn = document.getElementById('btn');
btn.addEventListener("click", test, false);
function test(e){
    e = e || window.event;
    alert((e.target || e.srcElement).innerHTML);
    btn.removeEventListener("click", test)
}
//IE9-:attachEvent()与detachEvent()。
//IE9+/chrom/FF:addEventListener()和removeEventListener()

IE9以下的IE浏览器不支撑 addEventListener()和removeEventListener(),运用 attachEvent()与detachEvent() 替代,由于IE9以下是不支撑事宜捕捉的,所以也没有第三个参数,第一个事宜称号前要加on。

3.DOM 3级事宜

在DOM 2级事宜的基础上增加了更多的事宜范例。

  • UI事宜,当用户与页面上的元素交互时触发,如:load、scroll
  • 核心事宜,当元素取得或落空核心时触发,如:blur、focus
  • 鼠标事宜,当用户经由历程鼠标在页面实行操纵时触发如:dblclick、mouseup
  • 滚轮事宜,当运用鼠标滚轮或相似装备时触发,如:mousewheel
  • 文本事宜,当在文档中输入文本时触发,如:textInput
  • 键盘事宜,当用户经由历程键盘在页面上实行操纵时触发,如:keydown、keypress
  • 合成事宜,当为IME(输入法编辑器)输入字符时触发,如:compositionstart
  • 更改事宜,当底层DOM构造发生变化时触发,如:DOMsubtreeModified
  • 同时DOM3级事宜也许可运用者自定义一些事宜。

二、DOM事宜模子和事宜流

DOM事宜模子分为捕捉和冒泡。一个事宜发生后,会在子元素和父元素之间流传(propagation)。这类流传分红三个阶段。

(1)捕捉阶段:事宜从window对象自上而下向目的节点流传的阶段;

(2)目的阶段:真正的目的节点正在处置惩罚事宜的阶段;

(3)冒泡阶段:事宜从目的节点自下而上向window对象流传的阶段。

DOM事宜捕捉的详细流程

《DOM事宜机制》

捕捉是从上到下,事宜先从window对象,然后再到document(对象),然后是html标签(经由历程document.documentElement猎取html标签),然后是body标签(经由历程document.body猎取body标签),然后依据一般的html构造一层一层往下传,末了抵达目的元素。

而事宜冒泡的流程刚好是事宜捕捉的逆历程。
接下来我们看个事宜冒泡的例子:

// 例3
<div id="outer">
    <div id="inner"></div>
</div>
......
window.onclick = function() {
    console.log('window');
};
document.onclick = function() {
    console.log('document');
};
document.documentElement.onclick = function() {
    console.log('html');
};
document.body.onclick = function() {
    console.log('body');
}
outer.onclick = function(ev) {
    console.log('outer');
};
inner.onclick = function(ev) {
    console.log('inner');
};

《DOM事宜机制》

正如我们上面提到的onclick给元素的事宜行动绑定要领都是在当前元素事宜行动的冒泡阶段(或许目的阶段)实行的。

三、事宜代办(事宜托付)

由于事宜会在冒泡阶段向上流传到父节点,因而能够把子节点的监听函数定义在父节点上,由父节点的监听函数一致处置惩罚多个子元素的事宜。这类要领叫做事宜的代办(delegation)。

1.长处

  • 削减内存斲丧,进步机能

假设有一个列表,列表当中有大批的列表项,我们须要在点击每一个列表项的时刻相应一个事宜

// 例4
<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>

假如给每一个列表项逐一都绑定一个函数,那关于内存斲丧是非常大的,效力上须要斲丧许多机能。借助事宜代办,我们只须要给父容器ul绑定要领即可,如许不论点击的是哪个子女元素,都邑依据冒泡流传的通报机制,把容器的click行动触发,然后把对应的要领实行,依据事宜源,我们能够晓得点击的是谁,从而完成差别的事。

  • 动态绑定事宜

在许多时刻,我们须要经由历程用户操纵动态的增删列表项元素,假如一开始给每一个子元素绑定事宜,那末在列表发生变化时,就须要从新给新增的元素绑定事宜,给行将删去的元素解绑事宜,假如用事宜代办就会省去许多如许贫苦。

2.怎样完成

接下来我们来完成上例中父层元素 #list 下的 li 元素的事宜托付到它的父层元素上:

// 给父层元素绑定事宜
document.getElementById('list').addEventListener('click', function (e) {
  // 兼容性处置惩罚
  var event = e || window.event;
  var target = event.target || event.srcElement;
  // 推断是不是婚配目的元素
  if (target.nodeName.toLocaleLowerCase === 'li') {
    console.log('the content is: ', target.innerHTML);
  }
});

四、Event对象罕见的运用

  • event. preventDefault()

假如挪用这个要领,默许事宜行动将不再触发。什么是默许事宜呢?比方表单一点击提交按钮(submit)跳转页面、a标签默许页面跳转或是锚点定位等。

许多时刻我们运用a标签仅仅是想当做一个一般的按钮,点击完成一个功用,不想页面跳转,也不想锚点定位。

//要领一:
<a href="javascript:;">链接</a>

也能够经由历程JS要领来阻挠,给其click事宜绑定要领,当我们点击A标签的时刻,先触发click事宜,其次才会实行本身的默许行动

//要领二:
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick = function(e){
    e = e || window.event;
    return false;
}
</script>
//要领三:
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick = function(e){
    e = e || window.event;
    e.preventDefault();
}
</script>

接下来我们看个例子:输入框最多只能输入六个字符,怎样完成?

// 例5
 <input type="text" id='tempInp'>
 <script>
    tempInp.onkeydown = function(ev) {
        ev = ev || window.event;
        let val = this.value.trim() //trim去除字符串首位空格(不兼容)
        // this.value=this.value.replace(/^ +| +$/g,'') 兼容写法
        let len = val.length
        if (len >= 6) {
            this.value = val.substr(0, 6);
            //阻挠默许行动去除特别按键(DELETE\BACK-SPACE\方向键...)
            let code = ev.which || ev.keyCode;
            if (!/^(46|8|37|38|39|40)$/.test(code)) {
                ev.preventDefault()
            }
        }
    }
 </script>
  • event.stopPropagation() & event.stopImmediatePropagation()

event.stopPropagation() 要领阻挠事宜冒泡到父元素,阻挠任何父事宜处置惩罚顺序被实行。上面提到事宜冒泡阶段是指事宜从目的节点自下而上向window对象流传的阶段。
我们在例4的inner元素click事宜上,增加event.stopPropagation()这句话后,就阻挠了父事宜的实行,末了只打印了’inner’。

 inner.onclick = function(ev) {
    console.log('inner');
    ev.stopPropagation();
};

stopImmediatePropagation 既能阻挠事宜向父元素冒泡,也能阻挠元素同事宜范例的别的监听器被触发。而 stopPropagation 只能完成前者的结果。我们来看个例子:

<body>
  <button id="btn">click me to stop propagation</button>
</body>
......
const btn = document.querySelector('#btn');
btn.addEventListener('click', event => {
  console.log('btn click 1');
  event.stopImmediatePropagation();
});
btn.addEventListener('click', event => {
  console.log('btn click 2');
});
document.body.addEventListener('click', () => {
  console.log('body click');
});
// btn click 1

如上所示,运用 stopImmediatePropagation后,点击按钮时,不仅body绑定事宜不会触发,与此同时按钮的另一个点击事宜也不触发。

  • event.target & event.currentTarget

老实说这两者的区分,并不好用文字描述,我们先来看个例子:

<div id="a">
  <div id="b">
    <div id="c">
      <div id="d"></div>
    </div>
  </div>
</div>
<script>
  document.getElementById('a').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })
  document.getElementById('b').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })
  document.getElementById('c').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })
  document.getElementById('d').addEventListener('click', function(e) {
    console.log(
      'target:' + e.target.id + '&currentTarget:' + e.currentTarget.id
    )
  })
</script>

《DOM事宜机制》

当我们点击最里层的元素d的时刻,会顺次输出:

target:d&currentTarget:d
target:d&currentTarget:c
target:d&currentTarget:b
target:d&currentTarget:a

从输出中我们能够看到,event.target指向引发触发事宜的元素,而event.currentTarget则是事宜绑定的元素,只要被点击的谁人目的元素的event.target才会即是event.currentTarget也就是说,event.currentTarget始终是监听事宜者,而event.target是事宜的真正发出者

五、参考文章

    原文作者:浪里行舟
    原文地址: https://segmentfault.com/a/1190000017259386
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞