指令的处理过程,是 ng 的 Compile 过程的一部分,它们也是紧密联系的。继续深入指令的定义方法,首先就要对 Compile 的过程做更细致的了解。
前面说过, ng 对页面的处理过程:
$compile ,返回一个 link 函数。
scope 调用这个 link 函数。
$compile 最基本的使用方式:
  var link = $compile('<p>{{ text }}</p>');
  var node = link($scope);
  console.log(node);
上面的 $compile 和 link 调用时都有额外参数来实现其它功能。先看 link 函数,它形如:
  function(scope[, cloneAttachFn]
第二个参数 cloneAttachFn 的作用是,表明是否复制原始节点,及对复制节点需要做的处理,下面这个例子说明了它的作用:
  <div ng-controller="TestCtrl"></div>
  <div id="a">A {{ text }}</div>
  <div id="b">B </div>
  app.controller('TestCtrl', function($scope, $compile){
    var link = $compile($('#a'));
    //true参数表示新建一个完全隔离的scope,而不是继承的child scope
    var scope = $scope.$new(true);
    scope.text = '12345';
    //var node = link(scope, function(){});
    var node = link(scope);
    $('#b').append(node);
  });
cloneAttachFn 对节点的处理是有限制的,你可以添加 class ,但是不能做与数据绑定有关的其它修改(修改了也无效):
  app.controller('TestCtrl', function($scope, $compile){
    var link = $compile($('#a'));
    var scope = $scope.$new(true);
    scope.text = '12345';
    var node = link(scope, function(clone_element, scope){
      clone_element.text(clone_element.text() + ' ...'); //无效
      clone_element.text('{{ text2 }}'); //无效
      clone_element.addClass('new_class');
    });
    $('#b').append(node);
  });
修改无效的原因是,像 {{ text }} 这种所谓的 Interpolate 在 $compile 中已经被处理过了,生成了相关函数(这里起作用的是 directive 中的一个 postLink 函数),后面执行 link 就是执行了 $compile 生成的这些函数。当然,如果你的文本没有数据变量的引用,那修改是会有效果的。
前面在说自定义指令时说过, link 函数是由 compile 函数返回的,也就像前面说的,应该把改变 DOM 结构的逻辑放在 compile 函数中做。
$compile 还有两个额外的参数:
  $compile(element, transclude, maxPriority);
maxPriority 是指令的权重限制,这个容易理解,后面再说。
transclude 是一个函数,这个函数会传递给 compile 期间找到的 directive 的 compile 函数(编译节点的过程中找到了指令,指令的 compile 函数会接受编译时传递的 transclude 函数作为其参数)。
但是在实际使用中,除我们手工在调用 $compile 之外,初始化时的根节点 compile 是不会传递这个参数的。
在我们定义指令时,它的 compile 函数是这个样子的:
  function compile(tElement, tAttrs, transclude) { ... }
事实上, transclude 的值,就是 directive 所在的 原始 节点,把原始节点重新做了编译之后得到的 link 函数(需要 directive 定义时使用 transclude 选项),后面会专门演示这个过程。所以,官方文档上也把 transclude 函数描述成 link 函数的样子(如果自定义的指令只用在自己手动 $compile 的环境中,那这个函数的形式是可以随意的):
  {function(angular.Scope[, cloneAttachFn]}
所以记住,定义指令时, compile 函数的第三个参数 transclude ,就是一个 link ,装入 scope 执行它你就得到了一个节点。