本文目錄一覽:
- 1、angularjs的$compile函數如何配合apendTo使用???急急急,在線等~
- 2、AngularJS的指令 compile和link的區別及使用示例
- 3、JS正則表達式詳解
- 4、angular里.dirrective里的 compile什麼意思
- 5、angularjs中指令中的compile參數是在什麼時候運行的
angularjs的$compile函數如何配合apendTo使用???急急急,在線等~
tbody id=”tblPresetPositionList” style=”width:100%;”
加個class
tbody id=”tblPresetPositionList” class=”tableA” style=”width:100%;”
然後改成下面這樣;
$dom.appendTo(‘.tableA’);
AngularJS的指令 compile和link的區別及使用示例
controller,link,compile有什麼不同
//directives.js增加exampleDirective
phonecatDirectives.directive(‘exampleDirective’, function() {
return {
restrict: ‘E’,
template: ‘pHello {{number}}!/p’,
controller: function($scope, $element){
$scope.number = $scope.number + “22222 “;
},
link: function(scope, el, attr) {
scope.number = scope.number + “33333 “;
},
compile: function(element, attributes) {
return {
pre: function preLink(scope, element, attributes) {
scope.number = scope.number + “44444 “;
},
post: function postLink(scope, element, attributes) {
scope.number = scope.number + “55555 “;
}
};
}
}
});
//controller.js添加
dtControllers.controller(‘directive2’,[‘$scope’,
function($scope) {
$scope.number = ‘1111 ‘;
}
]);
//html
body ng-app=”phonecatApp”
div ng-controller=”directive2″
example-directive/example-directive
/div
/body
運行結果:
Hello 1111 22222 44444 55555 !
JS正則表達式詳解
RegExp是JS的正則表達式對象,實例化一個RegExp對象有 字面量 和 構造函數 2種方式。
字面量實例化RegExp對象
var reg=/js/gi;
開始和結束的斜線/是正則表達式的邊界,//中間的文本是正則表達式文本,後面的gi是正則表達式的修飾符。
構造函數實例化RegExp對象
var reg=new Regex(『js』,』gi』);
第一個參數是正則表達式文本,第二個參數是正則表達式修飾符。
global:RegExp 對象是否具有標誌 g。
ignoreCase:RegExp 對象是否具有標誌 i。
lastIndex:一個整數,標示開始下一次匹配的字元位置。
multiline:RegExp 對象是否具有標誌 m。
source:正則表達式的源文本。
RegExp 對象有 3 個方法:test()、exec() 以及 compile()。
test()
test() 方法檢索字元串中的指定值。返回值是 true 或 false。
示例:
var reg=/js/gi;
var result=reg.test(『I like js』);
結果:true
exec()
exec() 方法檢索字元串中的指定值。返回值是被找到的值。如果沒有發現匹配,則返回 null。
示例:
var reg=/js/gi;
var result=reg.exec(『I like JS』);
結果:JS
compile()
compile() 方法用於改變 RegExp。
compile() 既可以改變檢索模式,也可以添加或刪除第二個參數。
g:global全文搜索,如果不添加此參數,搜索到第一個匹配就會停止
i:ignore case 不區分大小寫,默認是區分大小寫的
m:multiple lines 多行搜索,默認只搜索第一行
正則表達式文本部分包含 原義文本字元 和 元字元, 其中的原義文本字元代表字元本身意義的字元,如abc123之類的字元。
元字元代表有特殊含義非字母字元,如\b、\w、\d、+、*、? 等。
常用的元字元
更多的JS正則元字元請參考:
一般情況下正則表達式中的一個字元對應字元串中的一個字元,如表達式ab的含義是ab。
表達式中用 [] 來定義一個字元類,表示可以匹配[]裡面的這類字元,是一個泛指,而不是一一對應的關係。
如表達式[abc123],表示有其中一個字元串都可以匹配。
在字元類裡面使用橫線-連接2個數字或者字母就可以構建一個範圍類,如[a-zA-z0-9-]表示可以匹配26個大小寫字母和0-9的全部數字以及橫線-。
注意,要匹配橫線」-「,必須把橫線放在最後面。
預定義類可以理解為JS默認給我們寫好的範圍類,讓我們可以使用一個簡單的元字元來使用它。如」\w」就是一個預定義類,它等價於範圍類[A-Za-z0-9_];「.」可以匹配除 「\n」 之外的任何單個字元。
邊界包含2種,一種是以字元串開始或結尾的邊界,另一種是單詞邊界
量詞表示可以匹配連續多次的元字元
JS正則表達式默認是貪婪模式匹配,它會以最多匹配原則進行查找,非貪婪模式可以讓表達式以最少匹配原則進行查找。
非貪婪模式只需要在量詞後面加上」?」即可,如」123456789″字元串想以3個數字為一組進行匹配表達式寫法/\d{3,5}?/g。
表達式中用 () 來定義一個分組,使元字元可以作用於一個表達式字元串組合,如/(js|php){3}/gi。
表達式中的每一個分組匹配的內容都是一個可以捕獲的變數,可以使用$1、$2、$3… 來取值,如表達式/(\d{4})-(\d{2})-(\d{2})/中包含$1、$2、$3。如果想忽略分組匹配的內容,需要在分組前面增加「?:」,就可以得到分組匹配之外的內容。
前瞻就是正則表達式後面加上斷言部分,它不但要匹配表達式部分,還需要滿足斷言部分,匹配的結果不會包含斷言部分。
正向前瞻 exp(?=assert) 如 「\w(?=\d)」
負向前瞻 exp(?!assert) 如 「\w(?!\d)」
match()
stringObject.match(regexp)
match() 方法可在字元串內檢索指定的值,或找到一個或多個正則表達式的匹配。
如果 regexp 沒有標誌 g,那麼 match() 方法就只能在 stringObject 中執行一次匹配。
如果沒有找到任何匹配的文本, match() 將返回 null。
否則,它將返回一個數組,其中存放了與它找到的匹配文本有關的信息。該數組的第 0 個元素存放的是匹配文本,而其餘的元素存放的是與正則表達式的子表達式匹配的文本。
search()
stringObject.search(regexp)
search() 方法不執行全局匹配,它將忽略標誌 g。它同時忽略 regexp 的 lastIndex 屬性,並且總是從字元串的開始進行檢索,這意味著它總是返回 stringObject 的第一個匹配的位置。
replace()
stringObject.replace(regexp/substr,replacement)
字元串 stringObject 的 replace() 方法執行的是查找並替換的操作。它將在 stringObject 中查找與 regexp 相匹配的子字元串,然後用 replacement 來替換這些子串。如果 regexp 具有全局標誌 g,那麼 replace() 方法將替換所有匹配的子串。否則,它只替換第一個匹配子串。
replacement 可以是字元串,也可以是函數。如果它是字元串,那麼每個匹配都將由字元串替換。但是 replacement 中的 $ 字元具有特定的含義。如下表所示,它說明從模式匹配得到的字元串將用於替換。
split()
stringObject.split(separator,howmany)
如果 separator 是包含子表達式的正則表達式,那麼返回的數組中包括與這些子表達式匹配的字串(但不包括與整個正則表達式匹配的文本)
正則表達式語法語意測試工具:
angular里.dirrective里的 compile什麼意思
$compile,在Angular中即「編譯」服務,它涉及到Angular應用的「編譯」和「鏈接」兩個階段,根據從DOM樹遍歷Angular的根節點(ng-app)和已構造完畢的 \$rootScope對象,依次解析根節點後代,根據多種條件查找指令,並完成每個指令相關的操作(如指令的作用域,控制器綁定以及transclude等),最終返回每個指令的鏈接函數,並將所有指令的鏈接函數合成為一個處理後的鏈接函數,返回給Angluar的bootstrap模塊,最終啟動整個應用程序。[TOC]Angular的compileProvider拋開Angular的MVVM實現方式不談,Angular給前端帶來了一個軟體工程的理念-依賴注入DI。依賴注入從來只是後端領域的實現機制,尤其是javaEE的spring框架。採用依賴注入的好處就是無需開發者手動創建一個對象,這減少了開發者相關的維護操作,讓開發者無需關注業務邏輯相關的對象操作。那麼在前端領域呢,採用依賴注入有什麼與之前的開發不一樣的體驗呢?我認為,前端領域的依賴注入,則大大減少了命名空間的使用,如著名的YUI框架的命名空間引用方式,在極端情況下對象的引用可能會非常長。而採用注入的方式,則消耗的僅僅是一個局部變數,好處自然可見。而且開發者僅僅需要相關的「服務」對象的名稱,而不需要知道該服務的具體引用方式,這樣開發者就完全集中在了對象的借口引用上,專註於業務邏輯的開發,避免了反覆的查找相關的文檔。前面廢話一大堆,主要還是為後面的介紹做鋪墊。在Angular中,依賴注入對象的方式依賴與該對象的Provider,正如小結標題的compileProvider一樣,該對象提供了compile服務,可通過injector.invoke(compileProvider.$get,compileProvider)函數完成compile服務的獲取。因此,問題轉移到分析compileProvider.\$get的具體實現上。compileProvider.\$get this.\$get = [‘\$injector’, ‘\$parse’, ‘\$controller’, ‘\$rootScope’, ‘\$http’, ‘\$interpolate’, function(\$injector, \$parse, \$controller, \$rootScope, \$http, \$interpolate) { … return compile; } 上述代碼採用了依賴注入的方式注入了\$injector,\$parse,\$controller,\$rootScope,\$http,\$interpolate五個服務,分別用於實現「依賴注入的注入器(\$injector),js代碼解析器(\$parse),控制器服務(\$controller),根作用域(\$rootScope),http服務和指令解析服務」。compileProvider通過這幾個服務單例,完成了從抽象語法樹的解析到DOM樹構建,作用域綁定並最終返回合成的鏈接函數,實現了Angular應用的開啟。\$get方法最終返回compile函數,compile函數就是\$compile服務的具體實現。下面我們深入compile函數:function compile(\$compileNodes, maxPriority) { var compositeLinkFn = compileNodes(\$compileNodes, maxPriority); return function publicLinkFn(scope, cloneAttachFn, options) { options = options {}; var parentBoundTranscludeFn = options.parentBoundTranscludeFn; var transcludeControllers = options.transcludeControllers; if (parentBoundTranscludeFn parentBoundTranscludeFn.$$boundTransclude) { parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude; } var $linkNodes; if (cloneAttachFn) { $linkNodes = $compileNodes.clone(); cloneAttachFn($linkNodes, scope); } else { $linkNodes = $compileNodes; } _.forEach(transcludeControllers, function(controller, name) { $linkNodes.data(‘$’ + name + ‘Controller’, controller.instance); }); $linkNodes.data(‘$scope’, scope); compositeLinkFn(scope, $linkNodes, parentBoundTranscludeFn); return $linkNodes; }; } 首先,通過compileNodes函數,針對所需要遍歷的根節點開始,完成指令的解析,並生成合成之後的鏈接函數,返回一個publicLinkFn函數,該函數完成根節點與根作用域的綁定,並在根節點緩存指令的控制器實例,最終執行合成鏈接函數。合成鏈接函數的生成通過上一小結,可以看出\$compile服務的核心在於compileNodes函數的執行及其返回的合成鏈接函數的執行。下面,我們深入到compileNodes的具體邏輯中去:function compileNodes($compileNodes, maxPriority) { var linkFns = []; _.times($compileNodes.length, function(i) { var attrs = new Attributes($($compileNodes[i])); var directives = collectDirectives($compileNodes[i], attrs, maxPriority); var nodeLinkFn; if (directives.length) { nodeLinkFn = applyDirectivesToNode(directives, $compileNodes[i], attrs); } var childLinkFn; if ((!nodeLinkFn !nodeLinkFn.terminal) $compileNodes[i].childNodes $compileNodes[i].childNodes.length) { childLinkFn = compileNodes($compileNodes[i].childNodes); } if (nodeLinkFn nodeLinkFn.scope) { attrs.$$element.addClass(‘ng-scope’); } if (nodeLinkFn childLinkFn) { linkFns.push({ nodeLinkFn: nodeLinkFn, childLinkFn: childLinkFn, idx: i }); } }); // 執行指令的鏈接函數 function compositeLinkFn(scope, linkNodes, parentBoundTranscludeFn) { var stableNodeList = []; _.forEach(linkFns, function(linkFn) { var nodeIdx = linkFn.idx; stableNodeList[linkFn.idx] = linkNodes[linkFn.idx]; }); _.forEach(linkFns, function(linkFn) { var node = stableNodeList[linkFn.idx]; if (linkFn.nodeLinkFn) { var childScope; if (linkFn.nodeLinkFn.scope) { childScope = scope.$new(); $(node).data(‘$scope’, childScope); } else { childScope = scope; } var boundTranscludeFn; if (linkFn.nodeLinkFn.transcludeOnThisElement) { boundTranscludeFn = function(transcludedScope, cloneAttachFn, transcludeControllers, containingScope) { if (!transcludedScope) { transcludedScope = scope.$new(false, containingScope); } var didTransclude = linkFn.nodeLinkFn.transclude(transcludedScope, cloneAttachFn, { transcludeControllers: transcludeControllers, parentBoundTranscludeFn: parentBoundTranscludeFn }); if (didTransclude.length === 0 parentBoundTranscludeFn) { didTransclude = parentBoundTranscludeFn(transcludedScope, cloneAttachFn); } return didTransclude; }; } else if (parentBoundTranscludeFn) { boundTranscludeFn = parentBoundTranscludeFn; } linkFn.nodeLinkFn( linkFn.childLinkFn, childScope, node, boundTranscludeFn ); } else { linkFn.childLinkFn( scope, node.childNodes, parentBoundTranscludeFn ); } }); } return compositeLinkFn; } 代碼有些長,我們一點一點分析。首先,linkFns數組用於存儲每個DOM節點上所有指令的處理後的鏈接函數和子節點上所有指令的處理後的鏈接函數,具體使用遞歸的方式實現。隨後,在返回的compositeLinkFn中,則是遍歷linkFns,針對每個鏈接函數,創建起對應的作用域對象(針對創建隔離作用域的指令,創建隔離作用域對象,並保存在節點的緩存中),並處理指令是否設置了transclude屬性,生成相關的transclude處理函數,最終執行鏈接函數;如果當前指令並沒有鏈接函數,則調用其子元素的鏈接函數,完成當前元素的處理。在具體的實現中,通過collectDirectives函數完成所有節點的指令掃描。它會根據節點的類型(元素節點,注釋節點和文本節點)分別按特定規則處理,對於元素節點,默認存儲當前元素的標籤名為一個指令,同時掃描元素的屬性和CSS class名,判斷是否滿足指令定義。緊接著,執行applyDirectivesToNode函數,執行指令相關操作,並返回處理後的鏈接函數。由此可見,applyDirectivesToNode則是\$compile服務的核心,重中之重!applyDirectivesToNode函數applyDirectivesToNode函數過於複雜,因此只通過簡單代碼說明問題。上文也提到,在該函數中執行用戶定義指令的相關操作。首先則是初始化相關屬性,通過遍歷節點的所有指令,針對每個指令,依次判斷$$start屬性,優先順序,隔離作用域,控制器,transclude屬性判斷並編譯其模板,構建元素的DOM結構,最終執行用戶定義的compile函數,將生成的鏈接函數添加到preLinkFns和postLinkFns數組中,最終根據指令的terminal屬性判斷是否遞歸其子元素指令,完成相同的操作。其中,針對指令的transclude處理則需特殊說明:if (directive.transclude === ‘element’) { hasElementTranscludeDirective = true; var $originalCompileNode = $compileNode; $compileNode = attrs.$$element = $(document.createComment(‘ ‘ + directive.name + ‘: ‘ + attrs[directive.name] + ‘ ‘)); $originalCompileNode.replaceWith($compileNode); terminalPriority = directive.priority; childTranscludeFn = compile($originalCompileNode, terminalPriority); } else { var $transcludedNodes = $compileNode.clone().contents(); childTranscludeFn = compile($transcludedNodes); $compileNode.empty(); } 如果指令的transclude屬性設置為字元串「element」時,則會用注釋comment替換當前元素節點,再重新編譯原先的DOM節點,而如果transclude設置為默認的true時,則會繼續編譯其子節點,並通過transcludeFn傳遞編譯後的DOM對象,完成用戶自定義的DOM處理。在返回的nodeLinkFn中,根據用戶指令的定義,如果指令帶有隔離作用域,則創建一個隔離作用域,並在當前的dom節點上綁定ng-isolate-scope類名,同時將隔離作用域緩存到dom節點上;接下來,如果dom節點上某個指令定義了控制器,則會調用\$cotroller服務,通過依賴注入的方式(\$injector.invoke)獲取該控制器的實例,並緩存該控制器實例;隨後,調用initializeDirectiveBindings,完成隔離作用域屬性的單向綁定(@),雙向綁定(=)和函數的引用(),針對隔離作用域的雙向綁定模式(=)的實現,則是通過自定義的編譯器完成簡單Angular語法的編譯,在指定作用域下獲取表達式(標示符)的值,保存為lastValue,並通過設置parentValueFunction添加到當前作用域的$watch數組中,每次\$digest循環,判斷雙向綁定的屬性是否變髒(dirty),完成值的同步。最後,根據applyDirectivesToNode第一步的初始化操作,將遍歷執行指令compile函數返回的鏈接函數構造出成的preLinkFns和postLinkFns數組,依次執行,如下所示:_.forEach(preLinkFns, function(linkFn) { linkFn( linkFn.isolateScope ? isolateScope : scope, $element, attrs, linkFn.require getControllers(linkFn.require, $element), scopeBoundTranscludeFn ); }); if (childLinkFn) { var scopeToChild = scope; if (newIsolateScopeDirective newIsolateScopeDirective.template) { scopeToChild = isolateScope; } childLinkFn(scopeToChild, linkNode.childNodes, boundTranscludeFn); } _.forEachRight(postLinkFns, function(linkFn) { linkFn( linkFn.isolateScope ? isolateScope : scope, $element, attrs, linkFn.require getControllers(linkFn.require, $element), scopeBoundTranscludeFn ); }); 可以看出,首先執行preLinkFns的函數;緊接著遍歷子節點的鏈接函數,並執行;最後執行postLinkFns的函數,完成當前dom元素的鏈接函數的執行。指令的compile函數默認返回postLink函數,可以通過compile函數返回一個包含preLink和postLink函數的對象設置preLinkFns和postLinkFns數組,如在preLink針對子元素進行DOM操作,效率會遠遠高於在postLink中執行,原因在於preLink函數執行時並未構建子元素的DOM,在當子元素是個擁有多個項的li時尤為明顯。end of compile-publicLinkFn終於,到了快結束的階段了。通過compileNodes返回從根節點(ng-app所在節點)開始的所有指令的最終合成鏈接函數,最終在publicLinkFn函數中執行。在publicLinkFn中,完成根節點與根作用域的綁定,並在根節點緩存指令的控制器實例,最終執行合成鏈接函數,完成了Angular最重要的編譯,鏈接兩個階段,從而開始了真正意義上的雙向綁定。
angularjs中指令中的compile參數是在什麼時候運行的
在生成DOM後掃描並生成
angularJS肯定是在DOM節點樹生成後開始管理節點的,生成後尋找ng-app標記,然後其下屬所有節點均由ng來管理。使用compile可以改變原始的dom,在ng創建原始dom實例以及創建scope實例之前.
ng-repeat就是一個最好的例子,它就在是compile函數階段改變原始的dom生成多個原始dom節點,然後每個又生成element實例.
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/269962.html