前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从一个bug说jquery的事件注册和触发机制

从一个bug说jquery的事件注册和触发机制

作者头像
跑马溜溜的球
发布2020-12-07 15:33:14
8640
发布2020-12-07 15:33:14
举报
文章被收录于专栏:日积月累1024日积月累1024

问题描述

同一域名下有两个页面parent.html,child.html。parent.html中通过iframe嵌入child.html。父页面触发自定义事件,子页面对其进行响应。 两页面代码如下: 1.parent.html

代码语言:javascript
复制
<body>
    我是父页面
    <iframe></iframe>

    <script src="/js/jquery.min.js"></script>
    <script>
        $("iframe").attr('src', 'child.html');
        /*0.5s后触发自定义事件myevent*/
        setTimeout(function(){
            $(document).trigger('myevent');
        }, 500);
    </script>
</body>

2.child.html

代码语言:javascript
复制
<body>
    我是子页面

    <script src="/js/jquery.min.js"></script>
    <script>
        /*响应父页面myevent*/
        $(parent.document).bind("myevent",function(){
                console.log('i get it')
        })
    </script>
</body>

运行后,并没有在控制台输出”i get it”。也就是说子页面未能响应父页面的trigger(‘myevent’)。

分析

猜测了几个原因未果后,决定还是看下源码找问题。

  • bind方法对应jQuery.event.add。
  • trigger方法应jQuery.event.trigger,并最终落实到jQuery.event.handle执行。

我们来看看这两个方法吧(只摘说明问题需要的代码)

代码语言:javascript
复制
jQuery.event = {
       /*
        * elem:dom元素
        * types:事件
        * handler:处理函数
        */
    add : function(elem, types, handler, data){
        /*给处理函数指定唯一id*/
        handler.guid = this.guid++;
        /*从缓存中取出已有处理函数*/
        events = jQuery.data(elem, "events");
        handlers = events[type];
        /*以唯一id为key,存入新的处理函。*/
        handlers[handler.guid] = handler;
    },

    handle : function(event){
        /*取出dom元素上的所的事件处理函数, 顺次执行*/
        handlers = (jQuery.data(this, "events") || {})[event.type];
        for (var j in handlers){
            ...
        }
    }
}

两个方法均使用到了jQuery.data, 此函数只是拿来作缓存之用,所有数据存到了jQuery.cache。cache就是jQuery的一个内部变量,被初始化为{}。

代码语言:javascript
复制
jQuery.extend({
    cache: {},
    data: function(elem, name, data) {
        jQuery.cache[id][name] = data;
    }
})

注:以上代码摘自jquery-1.2.6版本,新版本代码要复杂一些,但实现机制类似。

至此,我们可以总结jQuery的事件注册/触发机制如下: - 对元素进行事件绑定(bind/on)时,事件会以elem->handles的kv对记录在内部缓存jQuery.cache中。 - 触发事件时,从cache中查找该元素对应的所有事件,依次执行。

bug原因

从以上分析不难看出,导致我们bug的原因如下: - 子页面的jQuery和父页面的jQuery是功能相同的两个不同对象。就像双胞胎,外表一致,内里却不尽相同。 - 子页面的myevent处理函数保存在了子页面的jQury.cache中 - 父页面的jQury.cache上没有myevent处理函数,触发时当然也不会有调用。

在jQuery内部代码的add和trigger中加log也可以看出这一点

这里写图片描述
这里写图片描述

解决

将child.html中的js代码改为

代码语言:javascript
复制
parent.$(parent.document).bind("myevent",function(){
    console.log('i get it')                                                       
});

如此一来,父子页面的事件触发,子页面的事件响应作用在了父页面的jQuery.cache上,问题得以解决。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-11-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题描述
  • 分析
  • bug原因
  • 解决
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档