Angular 与 jQuery 加载顺序的问题

最近打算把一个自己写的angular directive开源,于是花了点时间写demo,但是在demo里曾经没有什么问题的插件不能正常的工作,令人匪夷所思。 发现问题之后,困扰了一段时间,把所有能怀疑的对象都检查了一遍,依然没发现问题,最后在无意间对比过去使用这个directive的项目代码和demo代码发现二者的angular.js与jquery.js加载顺序不同,于是调换了一下顺序,果然问题就解决了。瞬间有种要掀桌的感觉(╯°Д°)╯︵ ┻━┻。 不过这个问题是为什么呢,百思不得其解,在Google了一番之后,在Google Group上找到了类似的问题。在原po的提示下,通过研究angular源码发现,原来angular会在加载到内存之后,查找 window.jQuery 如果存在,就对其进行扩展,并将jQLite绑定到jQuery上,以后创建出来的jQLite对象实际上也是jQuery对象。如果没找到,就使用angular自带的jQLite。以下是部分代码片段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function bindJQuery() {
// bind to jQuery if present;
jQuery = window.jQuery;
// reset to jQuery or default to us.
if (jQuery) {
jqLite = jQuery;
extend(jQuery.fn, {
scope: JQLitePrototype.scope,
isolateScope: JQLitePrototype.isolateScope,
controller: JQLitePrototype.controller,
injector: JQLitePrototype.injector,
inheritedData: JQLitePrototype.inheritedData
});
// Method signature:
// jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
jqLitePatchJQueryRemove('remove', true, true, false);
jqLitePatchJQueryRemove('empty', false, false, false);
jqLitePatchJQueryRemove('html', false, false, true);
} else {
jqLite = JQLite;
}
angular.element = jqLite;
}

Angular在加载到内存之后便会执行这段代码。以后所有的angular.element()创建或包装的对象都是jqLite对象。如果弄错了加载顺序,那么使用$()创建出来的对象与angular的jqLite对象便存在兼容性问题,导致一些奇怪的现象。

正确的做法

如果你要在项目中同时使用jQuery与AngularJS那么,一定要让jQuery在angularjs之前加载。比如下面这样写才能保证程序不出现奇怪的问题:

1
2
<script src="bower_components/jquery/jquery.js"></script>
<script src="bower_components/angular/angular.js"></script>