• 关于浏览器事件的思考



     先看下面的代码:

      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(),在你写通用的组件时候这个问题尤其突出。

  • 相关阅读:
    39.前端需要注意哪些SEO
    38.http的几种请求方法和区别
    37.伪元素和伪类的区别
    35.如何实现页面每次打开时清除本页缓存
    Jmeter工具设置中文版(切换显示语言)
    soapui测试http接口
    【C++】《Effective C++》第三章
    【C++】《Effective C++》第二章
    【设计模式】面向对象设计原则
    【设计模式】设计模式概述
  • 原文地址:https://www.cnblogs.com/baiduligang/p/4247409.html
Copyright © 2020-2023  润新知