zoukankan      html  css  js  c++  java
  • 关于浏览器事件的思考


     先看下面的代码:

      var $ = KISSY.all;

      $(‘a’).on(‘click’,function(e){

      doSomeThing();//这个方法貌似很有名

      e.halt();

      });

      上面的代码看起来像是很好的完成了我们交给它的工作,浏览器不会再将我们重定向到href中的链接,但这么做到底有什么不对呢?

      在解释有什么不对前,我们来看看浏览器中事件中的几个概念

      浏览器默认行为

      当我们点击某一个链接的时候,浏览器会直接跳转,在表单中按回车,表单会自动提交,这些都是浏览器的默认行为。

      Javascript事件传播的机制

      什么是事件冒泡?

      比如点击了一个按钮,这个元素上的事件被触发,同时该事件将会传播到它的所有父级元素中被触发。(a->div->body->document->window)这一过程被称为事件冒泡。事件冒泡是从子级元素到父级元素。

      注意:不是所有的事件都能冒泡,blur、focus、load和unload不能像其它事件一样冒泡

      什么是事件捕获?

      和事件冒泡恰恰相反,事件捕获是从父级元素到子级元素。

      什么是事件目标?

      简单的说也就是事件开始的那个元素,也就是上面说的a

      不同浏览器下的事件模型

      ● 支持W3C标准的浏览器:先捕获在冒泡。在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,为true,则采用事件捕获,为false,则采用事件冒泡。

      ● 不兼容W3C的浏览器(IE):IE只支持事件冒泡,它也不支持addEventListener函数,不过提供了attachEvent()方法来处理事件。

      看完上文,是否有感觉什么地方不对?没有?那再看看下文。

      ”halt“到底做了什么?

      当你每次调用”halt“的时候,它实际上做了2件事情:

      ● e.preventDefault();//阻止浏览器执行默认行为

      ● e.stopPropagation();//取消事件冒泡

      preventDefault和stopPropagation翻译成原生js后

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function preventDefault(e) {
    //如果提供了事件对象,则这是一个非IE浏览器
    if(e && e.preventDefault) {
      //阻止默认浏览器动作(W3C)
      e.preventDefault();
    } else {
      //IE中阻止函数器默认动作的方式
      window.event.returnValue = false;
    }
    return false;
    }
      
    function stopPropagation(e) {
    //如果提供了事件对象,则这是一个非IE浏览器
    if(e && e.stopPropagation) {
      //因此它支持W3C的stopPropagation()方法
      e.stopPropagation();
    } else {
      //否则,我们需要使用IE的方式来取消事件冒泡
      window.event.cancelBubble = true;
    }
    return false;
    }

      不是吧,我写最开始的代码只是想阻止浏览器的默认行为,不需要取消事件冒泡。

      但是,这样写也没有什么问题啊!(嘴硬,啪啪……)。

      确实,大多数情况下,这样的代码没有任何问题,那如果我们把这段代码放大到一个大环境中,会出现什么状况

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <div>
    <h2><a href="http://etao.com/page1">Page1</a></h2>
    <div>
        Teaser text...
    </div>
    </div>
    <div>
    <h2><a href="http://etao.com/page2">Page2</a></h2>
    <div>
        Teaser text...
     </div>
    </div>

      现在假设我们想要在用户点击文章标题时,将文章动态载入到div.content中(也就是doSomeThing做的事情),

      哈哈:上文的js代码也还是会执行啊(年轻人太急)。

      我们顺着这个思路继续,如果我想要在用户点击了一个div.post元素(或者任何一个它的子元素)时,给它加上一个active类,我就需要给div.post绑定click

    1
    2
    3
    4
    5
    var posts = $('div.post');
    posts.on('click',function () {
    posts.removeClass("active");
    $(this).addClass("active");
    });

      这个代码就会有时候执行有时候不执行,因为你在点击a的时候取消了事件冒泡。

      我们把这个代码的执行范围再次放大,产品提了一个需求,要求监听页面上所有的点击情况,一个同学接到需求,开心的在document上用了事件代理,向服务端发送了数据,回头数据一统计,似乎少了什么。回头一看,有人在a标签的点击事件中用了halt。

      其实这就是本文想传递的信息,大多数情况下,当你使用halt时,你其实真正需要的是e.preventDefault(),在你写通用的组件时候这个问题尤其突出。

  • 相关阅读:
    oracle中Blob和Clob类型的区别
    为什么要分库分表
    Enable file editing in Visual Studio's debug mode
    SQL Server Dead Lock Log
    Debug .NET Framework Source
    SQL Server text field里面有换行符的时候copy到excel数据会散乱
    诊断和修复Web测试记录器(Web Test Recorder)问题
    Can't load Microsoft.ReportViewer.ProcessingObjectModel.dll
    'telnet' is not recognized as an internal or external command
    Linq to XML
  • 原文地址:https://www.cnblogs.com/baiduligang/p/4247408.html
Copyright © 2011-2022 走看看