事件流 事件冒泡和事件捕获

Posted zjx304

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了事件流 事件冒泡和事件捕获相关的知识,希望对你有一定的参考价值。

事件冒泡和事件捕获

他们是描述事件触发时序问题的术语。

DOM标准规定事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。
捕获型事件流:事件的传播是从最不特定的事件目标到最特定的事件目标。即从外部到内部。 
冒泡型事件流:事件的传播是从最特定的事件目标到最不特定的事件目标。即从内部到外部

事件冒泡

<body>
  <div class="parent">
    <div class="son">
      <div class="grandson"></div>
    </div>

  </div>
  <script src="../report/js/jquery.min.js"></script>
  <script>
    $(.parent).click(function()
      console.log()                    
    )
    $(.son).click(function()
      console.log()
    )
    $(.grandson).click(function()
      console.log(孙子)
    )
  </script>
</body>
</html>

事件冒泡 父子都绑定了事件,点击子元素,会触发子元素绑定的事件;同时也会触发父元素绑定的事件

    // 当点击 parent不与son grandson相交区域              打印结果为  父
    // 当点击 parent与son相交 而不与grandson相交区域       打印结果为  子-父
    // 当点击 parent  son grandson 三者相交区域           打印结果为  孙子-子-父
    // 这是因为 事件的触发顺序自内向外,这就是事件冒泡。
    
    // 若是在grandson 加上阻止事件冒泡
    // $(‘.grandson‘).click(function(e)
    //   console.log(‘孙子‘)
    //   e.stopPropagation()
    // )
    // 此时当点击 parent  son grandson 三者相交区域        打印结果为  孙子
    // 因为 e.stopPropagation() 阻止了冒泡向 son grandson 触发事件

 由于一些人会以为显示出来儿子在父亲里面的时候,自然点了儿子相当于点了父亲,所以这个例子我故意把两个盒子绝对定位在了两个不同的位置,所以点击事件给页面显示出来的位置是没关系的,而是跟html代码中的位置有关系。

使用绝对定位,把parent、son、grandson分别定位到互不重叠的地区,点击grandson       打印的结果依然为孙子-子-父

<body>
  <div class="parent" id="parent">
    <div class="son" id="son">
      <div class="grandson" id="grandson"></div>
    </div>

  </div>
  <script src="../report/js/jquery.min.js"></script>
  <script>
    
    // var parent = document.getElementsByClassName(‘parent‘)
    // var son=document.getElementsByClassName(‘son‘)
    // var grandson=document.getElementsByClassName(‘grandson‘)

    var parent = document.getElementById(‘parent‘)
    var son=document.getElementById(‘son‘)
    var grandson=document.getElementById(‘grandson‘)

    parent.addEventListener(‘click‘,function()
      console.log(‘父‘)  
    ,false)
    son.addEventListener(‘click‘,function()
      console.log(‘子‘)  
    ,false)
    grandson.addEventListener(‘click‘,function()
      console.log(‘孙子‘)  
    ,false)
  </script>
</body>

使用事件监听  默认为false是事件冒泡和jquey onclick一样也是默认事件冒泡      

点击 grandson时,打印结果 孙子-子-父

注意:

    var parent1 = document.getElementsByClassName(‘parent‘)
    console.log(parent1)
    // 打印结果:HTMLCollection [div#parent.parent, parent: div#parent.parent]

    var parent2 = document.getElementById(‘parent‘)
    console.log(parent2)
    // 打印结果:<div class=‘parent‘ id=‘parent‘>...</div>

 

    parent1.addEventListener(‘click‘,function()
      console.log(‘结果1‘)  
    ,false)
    // 结果报错 Uncaught TypeError: parent1.addEventListener is not a function


    parent2.addEventListener(‘click‘,function()
      console.log(‘结果2‘)  
    ,false)
    //使用getElementById能正确打印出结果2

 

使用jquey 和js 获取元素的不同

  <script>
    var parentid=$(‘#parent‘)
    console.log(parentid)
    // 打印结果 r.fn.init [div#parent.parent]

var parentclass=$(‘.parent‘) console.log(parentclass) // 打印结果 r.fn.init [div#parent.parent, prevObject: r.fn.init(1)]

var parent_js_id=document.getElementById(‘parent‘) console.log(parent_js_id) // 打印结果 <div class="parent" id="parent">....</div>

var parent_js_class=document.getElementsByClassName(‘parent‘) console.log(parent_js_class) // 打印结果 HTMLCollection [div#parent.parent, parent: div#parent.parent] </script>

 

事件捕获

  <script>
    var parent = document.getElementById(‘parent‘)
    var son=document.getElementById(‘son‘)
    var grandson=document.getElementById(‘grandson‘)

    parent.addEventListener(‘click‘,function()
      console.log(‘父‘)  
    ,true)
    son.addEventListener(‘click‘,function()
      console.log(‘子‘)  
    ,true)
    grandson.addEventListener(‘click‘,function()
      console.log(‘孙子‘)  

    ,true)
    
    // 改为true时 ,使用的是事件捕获 由外向内   
    // 点击  parent 时               打印结果 父
    // 点击  son 时                  打印结果 父-子
    // 点击  grandson时              打印结果 父-子-孙子
    
    // 也能使用e.stopPropagation() 
    // parent.addEventListener(‘click‘,function()
    //   console.log(‘父‘)  
    // ,true)
    // son.addEventListener(‘click‘,function(e)
    //   console.log(‘子‘)  
    //   e.stopPropagation()
    // ,true)
    // grandson.addEventListener(‘click‘,function()
    //   console.log(‘孙子‘)  

    // ,true)
    // 当点击 grandson时  不使用stopPropagation()    打印结果 父-子-孙子
    // 当点击 grandson时  使用stopPropagation()      打印结果 父-子
  </script>

 

return false

javascript的return false只会阻止默认行为,而是用jQuery的话则既阻止默认行为又防止对象冒泡。

<body>
  <div class="parent" id="parent">
    <div class="son" id="son">
      <div class="grandson" id="grandson">
        <a id="click" href="https://baidu.com">点击</a>
      </div>
    </div>

  </div>
  <script src="../report/js/jquery.min.js"></script>
  <script>
    $(‘.parent‘).click(function()
      console.log(‘父‘)                    
    )
    $(‘.son‘).click(function()
      console.log(‘子‘)
    )
    $(‘.grandson‘).click(function()
      console.log(‘孙子‘)
    )
    // jq
    $(‘#click‘).click(function()
      console.log(‘jq点击‘)
      // 在jq中使用 return false  即阻止默认行为,又阻止冒泡
      return false
    )
  //和上面同样效果
// $(‘#click‘).on(‘click‘,function() // console.log(‘点击‘) 打印结果 点击-孙子-子-父 不会执行a标签的跳转 // return false // ) // js var a=document.getElementById(‘click‘) a.onclick=function() console.log(‘点击‘) return false //打印结果 点击-孙子-子-父 不会执行a标签的跳转 // document.getElementById(‘click‘).addEventListener(‘click‘,function() // console.log(‘点击‘) // return false //打印结果 return false不执行 ????? // ) </script>

 

兼容不同浏览器的阻止事件冒泡和阻止默认行为

阻止事件冒泡

function stopBubble(e)  
//如果提供了事件对象,则这是一个非IE浏览器 
if ( e && e.stopPropagation ) 
    //因此它支持W3C的stopPropagation()方法 
    e.stopPropagation(); 
else 
    //否则,我们需要使用IE的方式来取消事件冒泡 
    window.event.cancelBubble = true; 

 

阻止事件默认行为

//阻止浏览器的默认行为 
function stopDefault( e )  
    //阻止默认浏览器动作(W3C) 
    if ( e && e.preventDefault ) 
        e.preventDefault(); 
    //IE中阻止函数器默认动作的方式 
    else 
        window.event.returnValue = false; 
    return false; 

 preventDefault它是事件对象(Event)的一个方法,作用是取消一个目标元素的默认行为。既然是说默认行为,当然是元素必须有默认行为才能被取消,如果元素本身就没有默认行为,调用当然就无效了。什么元素有默认行为呢?如链接<a>,提交按钮<input type=”submit”>等。当Event 对象的 cancelable为false时,表示没有默认行为,这时即使有默认行为,调用preventDefault也是不会起作用的。

 

事件注意点

  1. event代表事件的状态,例如触发event对象的元素、鼠标的位置及状态、按下的键等等;
  2. event对象只在事件发生的过程中才有效。

firefox里的event跟IE里的不同,IE里的是全局变量,随时可用;firefox里的要用参数引导才能用,是运行时的临时变量。
在IE/Opera中是window.event,在Firefox中是event;而事件的对象,在IE中是window.event.srcElement,在Firefox中是event.target,Opera中两者都可用。

下面两句效果相同:

function a(e)
    var e = (e) ? e : ((window.event) ? window.event : null); 
    var e = e || window.event; // firefox下window.event为null, IE下event为null

由于jq中已经封装好的代码,可以直接使用jq来兼容不同浏览器

 

绑定事件

事件绑定常用三种方法

1.嵌入到dom上

<body>
  <div onclick="btnOpen()">按钮</div>
  <script src="../report/js/jquery.min.js"></script>
  <script>
    function btnOpen()
        alert(1)
    
  </script>
</body>

 

ps 使用系统定义的关键字来为函数命名,无效。

<body>
  <div onclick="open()">按钮</div>
  <script src="../report/js/jquery.min.js"></script>
  <script>
    function open()
        alert(1)
    
  </script>
</body>

 

2.直接绑定 

<body>
  <div id="btn">按钮</div>
  <script src="../report/js/jquery.min.js"></script>
  <script>
    document.getElementById(btn).onclick(function()
      console.log(点击)
    )
  </script>
</body>

 

3.事件监听

<body>
  <div id="btn">按钮</div>
  <script src="../report/js/jquery.min.js"></script>
  <script>
    document.getElementById(btn).addEventListener(click,function()
      console.log(按钮)
    )
    
  </script>
</body>

 

    // addEventListener(event, function, useCapture)
    //  event 事件名      function 事件触发执行的函数   
    // useCapture 默认为false 事件在冒泡阶段执行    true 事件在捕获阶段执行

 

以上是关于事件流 事件冒泡和事件捕获的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript事件冒泡和事件捕获

事件流(事件冒泡事件捕获和DOM事件流)

事件流事件冒泡和事件捕获

javascript中的事件冒泡事件捕获和事件执行顺序

聊聊事件冒泡与事件捕获

事件流,事件捕获与事件冒泡-基础知识总结------彭记(018)