dom 事件

216 阅读4分钟

dom类型

dom 0 onclick

<script>
var btn=document.getElementById("#btn");
btn.onclick=function(){
    alert(hello world!)
}
</script>

dom2 addevent listener

进一步规范后,有了DOM2级事件处理程序,我们可以通过类似如下代码,对一个元素的同一个事件添加多个处理程序

var btn=document.getElementById("#btn");
btn.addEventListener("click",function(){
    alert(hello world!)
})

btn.addEventListener("click",function(){
    alert(hello world2!)
})

dom3 支持多个事件比如 keyup

实际上,之前我们提到的addEventListener还有第三个参数,可以为true或false.当第三个参数为true时,绑定的是捕获阶段的事件,在捕获阶段,事件是由上到下依次触发的,反之当第三个参数为false时,绑定的是冒泡阶段的事件,在冒泡阶段,事件是由下到上触发的

DOM事件流的三个阶段:

事件捕获阶段

处于目标阶段

事件冒泡阶段

事件流代码 与 自定义事件

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <div id="ev" style="display: inline-block; width: 200px; height: 200px; background: red;">
    </div>

<script type="text/javascript">
    window.addEventListener('click', function () {
        console.log('window on click');
    }, true);

    document.addEventListener('click', function () {
        console.log('document on click');
    }, true);

    document.documentElement.addEventListener('click', function () {
        console.log('html on click');
    }, true);

    document.getElementById("ev").addEventListener('click', function () {
        console.log('ev on click');
    }, true);

    document.body.addEventListener('click', function () {
        console.log('body on click');
    }, true);
    // event
    var event = new Event('ccc');

    let ev = document.getElementById('ev');

    ev.addEventListener('ccc', function () {
        console.log('cccdddd');
    });


    // custom event, 数据必须定义在 detail 里
    var cevent = new CustomEvent('kkkk', {detail: 'ac'});

    ev.addEventListener('kkkk', function (e) {
        console.log(e.detail);
    });

    ev.dispatchEvent(event);
    ev.dispatchEvent(cevent);
</script>

</body>
</html>

event 对象常见方法

event.preventDefault()

阻止默认跳转行为

<!DOCTYPE html>
<html>
<body>

<a id="myAnchor" href="https://w3schools.com/">Go to W3Schools.com</a>

<p>The preventDefault() method will prevent the link above from following the URL.</p>

<script>
document.getElementById("myAnchor").addEventListener("click", function(event){
  event.preventDefault()
});
</script>

</body>
</html>

event.stopPropagation();

阻止冒泡

stopImmediatePropagation();

阻止同一个 dom上的事件的传播,又阻止冒泡

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

  btn.addEventListener('click', event => {
   console.log('btn click 3');
 });
 document.body.addEventListener('click', () => {
   console.log('body click');
 });
</script>
</body>
</html>

结果 btn click 1 btn click 2 出现 btn click1, 没有出现btn click3 是因为根据注册顺序执行的

target vs current target

从输出中我们可以看到,event.target指向引起触发事件的元素,而event.currentTarget则是事件绑定的元素,只有被点击的那个目标元素的event.target才会等于event.currentTarget。也就是说,event.currentTarget始终是监听事件者,而event.target是事件的真正发出者。

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <title>Example</title>
 5 </head>
 6 <body>
 7     <div id="A">
 8         <div id="B">
 9         </div>
10     </div>
11 </body>
12 </html>
var a = document.getElementById('A'),
      b = document.getElementById('B');    
function handler (e) {
    console.log(e.target);
    console.log(e.currentTarget);
}
a.addEventListener('click', handler, false);

当点击A时:输出:

1 <div id="A">...<div>
2 <div id="A">...<div>

当点击B时:输出:

1 <div id="B"></div>
2 <div id="A">...</div>

复制代码也就是说,currentTarget始终是监听事件者,而target是事件的真正发出者。由于要兼容IE浏览器,所以一般都在冒泡阶段来处理事件,此时target和currentTarget有

vue 时间捕获冒泡

<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

ie 事件与chrome 事件的不同

标准事件对象使用 event 的 target 属性获取事件目标。

var btn = document.getElementById('myButton');
btn.addEventListener("click", function(event) {
    alert(event.target.id);    // myButton
});

IE 事件对象使用 event 的 srcElement 属性获取事件目标。

var btn = document.getElementById("myButton");
btn.attachEvent("onclick", function(event) {
    alert(event.srcElement.id);    // myButton
});

另外,标准事件对象还有一个 currentTarget 属性,该属性在事件处理函数当中始终与 this 相等,而 target 属性则是指向事件触发的具体目标。

document.body.addEventListener("click", function (event) {
    alert(event.currentTarget.id);    // myBody
    alert(event.target.id);           // myButton
    alert(this.id);                   // myBody
});

事件代理

原理是利用冒泡原理,减少对dom 事件的绑定。

那什么样的事件可以用事件委托,什么样的事件不可以用呢?适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。值得注意的是,mouseover和mouseout虽然也有事件冒泡,但是处理它们的时候需要特别的注意,因为需要经常计算它们的位置,处理起来不太容易。不适合的就有很多了,举个例子,mousemove,每次都要计算它的位置,非常不好把控,在不如说focus,blur之类的,本身就没用冒泡的特性,自然就不能用事件委托了。