本文目录一览:
- 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实例.