在angular中會有基本的jquery-lite,也就是angular.element
,當在include angular之前,就先include jquery,此時angular的jquery-lite,就會被自動替換成jquery。
替換angular.element的source code如下:
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; }
|
另外一個需要注意的地方就是jqLitePatchJQueryRemove
,會將jquery原生的function
,多經過一層處理,處理完在呼叫jquery的function
。
jqLitePatchJQueryRemove的source如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) { var originalJqFn = jQuery.fn[name]; originalJqFn = originalJqFn.$original || originalJqFn; removePatch.$original = originalJqFn; jQuery.fn[name] = removePatch; function removePatch(param) { // jshint -W040 var list = filterElems && param ? [this.filter(param)] : [this], fireEvent = dispatchThis, set, setIndex, setLength, element, childIndex, childLength, children; if (!getterIfNoArguments || param != null) { while(list.length) { set = list.shift(); for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) { element = jqLite(set[setIndex]); if (fireEvent) { element.triggerHandler('$destroy'); } else { fireEvent = !fireEvent; } for(childIndex = 0, childLength = (children = element.children()).length; childIndex < childLength; childIndex++) { list.push(jQuery(children[childIndex])); } } } } return originalJqFn.apply(this, arguments); } }
|
其中element.triggerHandler('$destroy')
會告知angular底下的transcludedScope
,這個element已經被摧毀了,所以會導致,$element.detach
的時候,transcludedScope
無法被更新。element.triggerHandler('$destroy')
的監聽event可以參考createBoundTranscludeFn
這個function,會有下這段code去監聽:
1
| clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
|
在jqLitePatchJQueryRemove
只替換remove
、empty
、html
,而沒有替換detach
,使用detach
卻會影響scope
,真正原因要找jquery的source code。
因為detach間接呼叫了remove:
1 2 3
| detach: function( selector ) { return this.remove( selector, true ); }
|
Example(1.2.7):
由此可知,只要scope尚未ready時,呼叫detach
就不會中斷scope的更新。若要讓directive
的scope正常運作,可用以下方式:
- 不使用transclude
- 不在scope ready中,使用detach
- 使用原生api
- 最後一種方式,jquery在angular之後include
如果不是這麼需要使用到jquery,建議就不要include了,當然jquery也提供很多方便的功能,依照project需求自己評估吧!