function $CompileProvider($provide) {
var hasDirectives = {};
...
this.directive = function registerDirective(name, directiveFactory) {...};
...
this.$get = [
'$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
'$controller', '$rootScope', '$document',
function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
$controller, $rootScope, $document) {
...
return compile;
function compile($compileNodes, transcludeFn, maxPriority) {
var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority);
return function publicLinkFn(scope, cloneConnectFn){
var $linkNode = cloneConnectFn
? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
: $compileNodes;
// 把scope连接到节点
for(var i = 0, ii = $linkNode.length; i<ii; i++) {
var node = $linkNode[i];
if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
$linkNode.eq(i).data('$scope', scope);
}
}
//在链接节点上添加class ng-scope
safeAddClass($linkNode, 'ng-scope');
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
//
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
return $linkNode;
};
}
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority) {
var linkFns = [],
nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
/**
* 下面这一坨就是从nodeList和他们的子节点中找出所有的指令相关的linkFn,放入nodeLinkFn,和childLinkFn中
*/
for(var i = 0; i < nodeList.length; i++) {
attrs = new Attributes();
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
directives = collectDirectives(nodeList[i], [], attrs, maxPriority);
nodeLinkFn = (directives.length)
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
: null;
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length)
? null
: compileNodes(nodeList[i].childNodes,
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
linkFns.push(nodeLinkFn);
linkFns.push(childLinkFn);
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
}
/* 结束后的到linkFns数组,包含了所有的linkFn,注意,nodeLinkFn与它的childLinkFn连续放置,
* 即linkFns = [nodeLinkFn1, childLinkFn1, nodeLinkFn2, childLinkFn2, ... ]
* 并返回linkFnFound = true/false
*/
return linkFnFound ? compositeLinkFn : null;
//返回复杂链接的方法
function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn, i, ii, n;
//拷贝nodelist, 你懂的
var stableNodeList = [];
for (i = 0, ii = nodeList.length; i < ii; i++) {
stableNodeList.push(nodeList[i]);
}
//遍历由nodeList中找出来的linkFns,做下面的事情:
//
for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
node = stableNodeList[n];
nodeLinkFn = linkFns[i++];
childLinkFn = linkFns[i++];
if (nodeLinkFn) {
//判断是否需要生成新的scope
if (nodeLinkFn.scope) {
childScope = scope.$new(isObject(nodeLinkFn.scope)); //为他的子节点新建一个scope域
jqLite(node).data('$scope', childScope);
} else {
childScope = scope;
}
//是否穿透
childTranscludeFn = nodeLinkFn.transclude;
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
nodeLinkFn(childLinkFn, childScope, node, $rootElement,
(function(transcludeFn) {
return function(cloneFn) {
var transcludeScope = scope.$new();
transcludeScope.$$transcluded = true;
return transcludeFn(transcludeScope, cloneFn).
bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
};
})(childTranscludeFn || transcludeFn)
);
} else {
//执行nodelinkFn
nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
}
} else if (childLinkFn) {
childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
}
}
}
}
function collectDirectives(node, directives, attrs, maxPriority) { ... }
function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection) {
return nodeLinkFn;
function addLinkFns(pre, post) { ... }
function getControllers(require, $element) { ... }
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) { ... }
}
function addDirective(tDirectives, name, location, maxPriority) { ... }
function compileTemplateUrl(directives, beforeTemplateNodeLinkFn, $compileNode, tAttrs, $rootElement, replace, childTranscludeFn) {
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) { ... };
}
function assertNoDuplicate(what, previousDirective, directive, element) { ... }
function addTextInterpolateDirective(directives, text) { ... }
function addAttrInterpolateDirective(node, directives, value, name) { ... }
function replaceWith($rootElement, $element, newNode) { ... }
}];
}
/**
* 在给定的节点上查找指令并放入排序的directives集合里面
*
* @param node Node to search.
* @param directives An array to which the directives are added to. This array is sorted before
* the function returns.
* @param attrs The shared attrs object which is used to populate the normalized attributes.
* @param {number=} maxPriority Max directive priority.
*/
function collectDirectives(node, directives, attrs, maxPriority) {
var nodeType = node.nodeType,
attrsMap = attrs.$attr,
match,
className;
switch(nodeType) {
case 1: /* Element */
// use the node name: <directive> 节点有对应的<directive>,对应“E”类型
addDirective(directives,
directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority);
// 属性上是否有相应的directive, 对应“A”类型
for (var attr, name, nName, value, nAttrs = node.attributes,
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
attr = nAttrs[j];
if (attr.specified) {
name = attr.name;
nName = directiveNormalize(name.toLowerCase());
attrsMap[nName] = name;
attrs[nName] = value = trim((msie && name == 'href')
? decodeURIComponent(node.getAttribute(name, 2))
: attr.value);
if (getBooleanAttrName(node, nName)) {
attrs[nName] = true; // presence means true
}
addAttrInterpolateDirective(node, directives, value, nName);
addDirective(directives, nName, 'A', maxPriority);
}
}
// class上是否有相应的directive,对应“C”类型
className = node.className;
if (isString(className) && className !== '') {
while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
nName = directiveNormalize(match[2]);
if (addDirective(directives, nName, 'C', maxPriority)) {
attrs[nName] = trim(match[3]);
}
className = className.substr(match.index + match[0].length);
}
}
break;
case 3: /* Text Node */
//文本类型特殊处理,先不看吧~
addTextInterpolateDirective(directives, node.nodeValue);
break;
case 8: /* Comment */
//注释上是否有相应的directive, 对应“M”类型
try {
match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
if (match) {
nName = directiveNormalize(match[1]);
if (addDirective(directives, nName, 'M', maxPriority)) {
attrs[nName] = trim(match[2]);
}
}
} catch (e) {
// turns out that under some circumstances IE9 throws errors when one attempts to read comment's node value.
// Just ignore it and continue. (Can't seem to reproduce in test case.)
}
break;
}
//优先级排序
directives.sort(byPriority);
return directives;
}