事件机制,事件委托,stopprogation和stop preventdefault

316 阅读2分钟

事件机制

image.png
事件机制分为三个阶段: 捕获阶段、目标阶段、冒泡阶段,三个阶段依次执行

addEventListener

三个参数: 事件类型、回调函数、捕获还是冒泡(默认false,冒泡) addEventListener("click",function(){},true);

事件代理(事件委托)

“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown......)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡

用法:
【1】可以大量节省内存占用,减少事件注册,比如在ul上代理所有li的click事件

<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>
// ...... 代表中间还有未知数个 li


【2】可以实现当新增子对象时无需再次对其绑定(动态绑定事件)
假设上述的例子中列表项li就几个,我们给每个列表项都绑定了事件;

在很多时候,我们需要通过 AJAX 或者用户操作动态的增加或者删除列表项li元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件;

如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的;所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的

target currentTarget

event.target 返回触发事件的元素(在点击事件中,就相当于被你点击的那个元素对象) event.currentTarget 返回绑定事件的元素,即事件的委托对象(绑定了事件处理函数的元素)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <ul>
    <li>hello 1</li>
    <li>hello 2</li>
    <li>hello 3</li>
    <li>hello 4</li>
  </ul>
  <script>
    let ul = document.querySelectorAll('ul')[0]
    let aLi = document.querySelectorAll('li')
    ul.addEventListener('click',function(e){
       let oLi1 = e.target  
       let oLi2 = e.currentTarget
        console.log(oLi1)   //  被点击的li
        console.log(oLi2)   // ul
        console.og(oLi1 === oLi2)  // false
    })
  </script>
</body>
</html>

stopprogation和stop preventdefault

preventDefault是用来阻止浏览器的默认事件,stopPropagation是用来阻止冒泡事件(父子元素之间)

preventDefault:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <form>
    <label for="check1">Checkbox:</label>
    <input type="checkbox" id="check1"/>
  </form>
  <a id='link1' target="_blank"  href="https://www.baidu.com/">BaiDu</a> 
  
  <script>
    const  aDom=document.getElementById('link1')
    const  inputDom=document.getElementById('check1') 
    function bindEvent(ele,type,fn){
          ele.addEventListener(type,fn)
    }
    bindEvent(aDom,'click',(event)=>{    
        event.preventDefault();    
        alert("我是a标签,启用阻止默认事件,不能跳转") 
    })
    bindEvent(inputDom,'click',(event)=>{    
        event.preventDefault();   
        alert("我是多选框,启用阻止默认事件,不能点击选中")   
    }) 

  </script>

</body>
</html>

stopPropagation

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  .out{
    width: 200px;
    height: 200px;
    background-color: rgb(202, 235, 20);
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .inner{
    width: 100px;
    height: 100px;
    background-color: rgb(27, 200, 223);
    
  }
</style>
<body>
  <div class="content">
    <div class="out">
      <div class="inner"></div>
    </div>
  </div>

  <script type="text/javascript">

    //注意:冒泡事件是发生在父子元素之间

    var out = document.getElementsByClassName("out")[0];

    var inner = document.getElementsByClassName("inner")[0];

    out.addEventListener("click", function (evt) {

      alert("触发了out的点击事件");
      console.log('out');

    }, false);

    inner.addEventListener("click", function (evt) {

      alert("触发了inner的点击事件");
      console.log('inner');

      //在此处调用stopPropagation()会阻止冒泡事件

      // evt.stopPropagation();

    }, false);

  </script>

</body>
</html>