惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
博客园 - 司徒正美
Last Week in AI
Last Week in AI
Recent Announcements
Recent Announcements
Y
Y Combinator Blog
博客园 - 聂微东
M
MIT News - Artificial intelligence
博客园_首页
Jina AI
Jina AI
博客园 - 叶小钗
酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
F
Fortinet All Blogs
aimingoo的专栏
aimingoo的专栏
小众软件
小众软件
Vercel News
Vercel News
The Cloudflare Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
云风的 BLOG
云风的 BLOG
N
Netflix TechBlog - Medium
B
Blog
Google DeepMind News
Google DeepMind News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - BAsil

ubuntu下安装git server以及eclipse egit插件配置 windows下调试android源代码 Mac OS 10.6(Snow Leopard)编译Android源代码 使用Mono Runtime Bundle制作安装包让C#桌面应用程序脱离net framework c++对象成员函数返回自身引用时出现的诡异问题及解决办法 C++指针存储结构 重构一个贪吃蛇游戏(linux c++) Ubuntu 9.10 Server 配置Apache + WebDav 实现文档协同管理 javascript 事件机制 与 jQuery.Bind Ubuntu 9.10 Server 配置基于SSL的Subversion Ubuntu 9.10 Server (Karmic) 迁移Bugzilla 域环境下配置连接sql server 的asp.net网站 注意IIS 7.0的集成管道模式下HttpApplication 请求管道事件的问题 出现Unable to launch Visual Studio's Localhost Web Server问题解决 基于TCP的网络游戏黑白棋系列(四):游戏棋盘 基于TCP的网络游戏黑白棋系列(三):游戏大厅 基于TCP的网络游戏黑白棋系列(二):数据传输 基于TCP的网络游戏黑白棋系列(一):建立连接 基于TCP的网络游戏黑白棋系列教程开篇
javascript事件机制与jQuery.bind的补充说明
BAsil · 2010-05-10 · via 博客园 - BAsil

在之前的文章javascript 事件机制 与 jQuery.Bind中,为了说明冒泡阶段中Event Handler Function的表现,我使用了event.data来记录触发function的次数。并且提出了一个问题,就是在jQuery.bind方式中,event.data无法正确记录触发的次数。后来经过测试和查阅网上的相关的资料,得出了一个结论,就是我之前关于event.data的使用方式是错误的,或者说对于跨浏览器的支持是困难的。同时我也意识到,由于event.data在w3c dom level 2文档中,并不是作为event的标准属性出现的,所以jQuery对event进行了fix,使其能够兼容各个浏览器。

在我纠正误用event.data的方式之前,再描述一下我对event的理解。在我查看jQuery(1.3.2)源代码的时候,jQuery.event的add方法中有如下代码

// Init the element's event structure
var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
    handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function() {
         // Handle the second event of a trigger and when
         // an event is called after a page has unloaded
         return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
                jQuery.event.handle.apply(arguments.callee.elem, arguments) :
                undefined;
        });

其中的jQuery.event.handle中进行event的fix

event = arguments[0] = jQuery.event.fix(event || window.event);

这里按照网上的资料大多是说ie下使用window.event,而firefox下使用arguments[0]也就是传递过来的函数参数event。可我在测试中发现ie6,ie7(未测试),ie8在fix之前event并不为空,也就是说在fix的时候并没有使用window.event。

看一下这段代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>    
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
<title></title>
<style>
     #panelGrandPa,#panelPaPa,#panelSon  { border:1px  solid #320213;}
 </style>
</head>
 <body>
<div id="panelGrandPa" style="width:300px;height:200px;" >
       <div id="panelPaPa" style="width:200px;height:100px;" >
            <div id="panelSon" style="width:100px;height:50px;" >
                    
            </div>
       </div>
</div>
<script>
    function click() {
        alert(event.srcElement.id);
        event.data = event.data || 1;
        alert("click function has fired  " + event.data + " times");
        event.data = parseInt(event.data) + 1;
    }
    function clickSon() {
        alert("I am son");
        click();
    }
    function clickGrandPa() {
        alert("I am GrandPa");
        click();
    }
    document.getElementById("panelGrandPa").onclick = clickGrandPa;
    document.getElementById("panelSon").onclick = clickSon;
</script>
</body>
</html>

只能在ie8下正常工作,在ie6和ie7下都报event.data undefined错误。当然我们这里使用的是window.event也就是页面维护的event相当于全局变量,那我们再试一下事件方法的event参数(之前阅读jQuery源代码提到的ie中除却window.event另外的event)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>    
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
<title></title>
<style>
     #panelGrandPa,#panelPaPa,#panelSon  { border:1px  solid #320213;}
 </style>
</head>
 <body>
<div id="panelGrandPa" style="width:300px;height:200px;" >
       <div id="panelPaPa" style="width:200px;height:100px;" >
            <div id="panelSon" style="width:100px;height:50px;" >
                    
            </div>
       </div>
</div>
<script>
    function click(e) {
        alert(event.srcElement.id);
        e.data = e.data || 1;
        alert("click function has fired  " + e.data + " times");
        e.data = parseInt(e.data) + 1;
    }
    function clickSon() {
        alert("I am son");
        click(arguments[0]);
    }
    function clickGrandPa() {
        alert("I am GrandPa");
        click(arguments[0]);
    }
    document.getElementById("panelGrandPa").attachEvent("onclick", clickGrandPa);
    document.getElementById("panelSon").attachEvent("onclick", clickSon);
</script>
</body>
</html>

注意必须用attachEvent我们才能得到区别于window.event的“另一个”event。以上代码在ie8下正常工作,在ie6和ie7下event.data始终为1


对于window.event,在ie6和ie7下,通过调试工具发现其中并没有event.data的属性。而attachEvent的得到的event.data 在ie6和ie7下不能正确计数,始终为1,但ie8下正确。

鉴于event在各浏览器下的差异以及我们对书写跨浏览器脚本的良好愿望,我个人认为不应该在多个事件方法中传递event.data。

当然jQuery在这方面做得更好经过fix后的event 使得event.data在各种浏览器下表现一致

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>    
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
 <script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.js"></script>
<title></title>
<style>
     #panelGrandPa,#panelPaPa,#panelSon  { border:1px  solid #320213;}
 </style>
<head>
<body>
<div id="panelGrandPa" style="width:300px;height:200px;" >
       <div id="panelPaPa" style="width:200px;height:100px;" >
            <div id="panelSon" style="width:100px;height:50px;" >
                    
            </div>
       </div>
</div>
<script>
    function click(e) {
        alert(e.target.id);
        e.data = e.data || 1;
        alert("click function has fired  " + e.data + " times");
        e.data = parseInt(e.data) + 1;
    }
    function clickSon(e) {
        alert("I am son");
        click(e);
    }
    function clickGrandPa(e) {
        alert("I am GrandPa");
        click(e);
    }
    $("#panelGrandPa").bind("click", clickGrandPa);
    $("#panelSon").bind("click", clickSon);
</script>
</body>
</html>

上述代码在任何浏览器下都不能正常计数,显示event.data为1(这下ie8也不行了)。

我们分析一下原因,这也是我对上一篇提出问题的一个回答

jQuery.event.add方法封装了attachEvent/addEventListener并且给每一个handler方法附加了data

add:function(elem, types, handler, data) {
    //省略部分代码
    // if data is passed, bind to handler
    if (data !== undefined) {
        // Create temporary function pointer to original handler
        var fn = handler;

        // Create unique handler function, wrapped around original handler
        handler = this.proxy(fn);

        // Store data in unique handler
        handler.data = data;
    }
    //省略部分代码
}


在jQuery.event的fix方法中,我们看到其将传入的event复制了一份(包括data),注意不是引用(这意味着每次方法的event都是不同的)

fix: function(event) {
    if (event[expando])
        return event;

    // store a copy of the original event object
    // and "clone" to set read-only properties
    var originalEvent = event;
    event = jQuery.Event(originalEvent);

    for (var i = this.props.length, prop; i; ) {
        prop = this.props[--i];
        event[prop] = originalEvent[prop];
    }
    //以下省略
}

那么这样一来,我们肯定不能在多个事件方法中用上述方法传递data了。