[关闭]
@yiranphp 2015-09-14T01:50:10.000000Z 字数 1955 阅读 2255

一个bug【jQuery conflict with angular material】的解决旅程

bug


bug描述:
特定版本的angularJs & angularJs Material & jQuery 之间的冲突(ipad上的safari

  1. jQuery:2.1.4
  2. angularJs:1.3.16
  3. angularJs Material:0.8.3

事情的起源是这样的:
最近手上的项目使用了上述三个(库/框架/插件)东东,

  1. jQuery:地球人都知道
  2. angularJs:现在也很流行,不知道的人估计很少吧
  3. angularJs Material:基于angular的一套组件库,看起来美观,舒服

某次在ipad上测试,发现了如下一个bug:
所有的事件处理函数都被执行了两次, 很多时候,一个函数被执行两次是不容易被发现的,但是一个alert弹窗,就很容易发现。发现了bug,就要debug,
这里debug的过程很繁琐,也不是本人debug,大致的思路就是,怀疑某些库之间的冲突了,经过不断的排查,得出结论:jQuery 和 angular Material之间冲突了。

解决问题的办法最初是这样的:因为是两个库之间的冲突,想修改库来解决这个问题是不太可能的了,所以是在绑定事件的代码上做了处理,在很短的一瞬间函数只会被执行一次。
因为我们的业务代码都是使用统一的事件绑定代码,所以修改起来也比较简单。这个问题就暂时告一段落了。
没过多久,又出状况了,在ipad上的复选框失效了,这里的复选框指的是Material的 md-checkbox,怀疑思路又是哪里冲突了,果然,经过排查,得出原因,竟是和上一次的bug原因一样,事件处理函数被执行了两次,只不过这一次不是我们业务里的事件绑定,而是checkbox的特殊性,试想,如果一个checkbox连续很短时间内被点击两次,是什么效果,效果就是好像没效果一样。
可是,问题来了,这一次事件的绑定是material 库里做的,要修改 material吗?也许matrial里还有其他的一些事件会受到影响,都要一一找到做修改吗?这显然不是好办法?
让我们再想一下,bug的产生原因:

所有的事件处理函数都被执行了两次

但是,更重要的是

这是jQuery和 material 之间的冲突产生的

material 和 jQuery之间是如何产生冲突的呢?
material是基于angularJs的一套组件库,而angularJs和jQuery之间的关系,就是有了jQuery,angular就会去使用它,没有jQuery就会去使用内置的jQuery简化版,jQlite
这里我做了一个假设:当引入了jQuery之后,angular就会去使用它,此时,会和material发生某种冲突,导致上述bug的产生,随即我做了验证,由于angularJs是寻找window.JQuery来判定的,所以我在引入jQuery之后把window.JQuery干掉,随后引入angularJs之后,再把window.JQuery恢复,不影响其他方面jQuery的使用,

<script>
    // jquery和 ngMaterial冲突, 因为angular是根据window.jQuery来判断的,所以先隐藏,欺骗angular
    if (window.jQuery) {
        window.hideJQuery = window.jQuery;
        window.jQuery = false;
    }
</script>

<script src="/src/bower_components/angular/angular.min.js"></script>

<script>
    // 骗完angular, 可以继续使用jquery了
    if (window.hideJQuery) {
        window.jQuery = window.hideJQuery;
        window.hideJQuery = undefined;
    }
</script>


发现问题消失了,这说明我的猜测是对的,那么解决问题的办法就是,在angular中屏蔽jQuery,让angular使用内置的jQlite,即便引入了jQuery。
然而,上面的代码看起来很有意思,但是并不优雅,想要优雅的解决这个问题,angularJs(>1.4)引入了一个新的指令,ngJq,可以强制使用内置的jQlite。
两天之后,我又突然想到,新版本的angularJs 或是 angular Material 会不会已经解决了这个问题呢,测试之后又发现,最新版的material 0.11.0 已经解决了这个问题,可以点击下面的链接,在chrome的ipad模拟器中测试对比
material 0.8.3版本和0.11.0版本的差别。

点击一下看结果:注意在ipad模拟器中测试
至此,这个bug算是得到了最完美的解决

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注