在编写指令时,我们都会有一个template或者templateUrl这样的属性是吧。在使用transclusion时,我们要把嵌入部分放到模板中,因此我们有两种选择,其中一种选择就是使用ng-transclude。
ng-transclude是干什么用的,我们还是先来看定义,再来看例子:
ng-tranclude决定了在什么地方放置嵌入部分。
太好理解了!于是我们来看例子:
假设指令是这样的:
<handsome-me> {{name}} </handsome-me>
而模板是这样的:
<div> <p>MaMa does not need to worry about my study anymore! </p> <div ng-transclude></div> </div>
于是,在transclude:true的情况下,最终呈现在页面中的HTML会是什么样子。对了,是这样:
<div> <p>MaMa does not need to worry about my study anymore! </p> {{name}} </div>
另一种情况,在transclude:'element'的情况下,最终呈现在页面中的HTML会是什么样子。对了,是这样:
<div> <p>MaMa does not need to worry about my study anymore! </p> <handsome-me> {{name}} </handsome-me> </div>
例子这么清楚,总能明白了吧!!
三、不使用ng-transclude的情形
OK,现在我们来想一个问题,如果我想把我的嵌入部分多次放入我的模板中怎么办?你可能会说,那就多放几个ng-transclude呗!这当然是不行的,在AngularJS中你只在一个指令的模板中只能申明一个ng-tranclude。所以这种情况下我们就能使用模板了,因此我们要使用一个叫做tranclude()的函数!!
纳尼!这又是什么东西!!!如果你仔细去研究一下AngularJS的文档的话,你一定会发现一个叫做$tranclude的service,它就是我们现在要将讲的东西。那么这个函数怎么用?如果你看过一些关于ng-repeat,ng-swift源码的解析,你一定会记得其中的一个叫做linker的东西。这个东西上是什么曾经困扰过我好长时间,但是后来我发现这个linker()其实就是transclude() 。
我们在link,compile以及controller中都能找到这个transclude函数的身影。在link函数中,transclude是link函数的第五个参数;在compile函数中,transclude是compile函数的第三个参数。在这个两个函数中,由于我们没有使用依赖注入,因此只要顺序对了就对了,随便命名为什么都可以。而在controller函数中,由于使用的是依赖注入,因此transclude是$transclude,只要名字写对了就对了。在link,compile和controller函数中,transclude的用法一模一样,因此在这我们只举一个link函数的例子:
1.最简单的用法:
link(scope,elem,attrs,ctrl,transclude){ var content = transclude(); elem.append(content); }
在这里,我们通过transclude()返回了嵌入部分的具体内容,然后append到了元素的elem的尾巴上,当然,你想要append多次也是可以的。
2.复杂一点的用法:
link(scope,elem,attrs,ctrl,transclude){ tranclude(scope,function(clone){ elem.append(clone); }) }
这里tranclude接受了两个参数,第一个是scope,代表作用域。第二个回调函数中带有一个参数clone,其实它就是嵌入内容,和transclude()的返回值一模一样。那么前面的第一个参数的scope有什么用呢?这就要说到transclude和作用域了!
4.transclude和scope
我们知道,在定义一个指令时,如果不显式声明scope,那么指令的作用域就是父作用域。如果声明scope:true或者scope:{} ,那么指令会生成一个自己的作用域,只不过一个原型继承,一个独立而已。如果你使用transclusion,那么无论什么情绪,都会生成一个新的作用域,这个作用域直接原型继承于父作用域,它的地位和指令生成的作用域是一样的,二者属于并列的关系。
于是我们现在就能了解tranclude(scope,function(clone){})中的scope是什么意思了,默认情况下,如果我们简单使用translude() ,那么作用域默认的是transclude生成的自作用域。但是如果我们使用tranclude(scope,function(clone){}) ,那么作用域显然就是directive的作用域了。要是我们想使用父作用域怎么办,很简单:
tranclude(scope.$parent,function(clone){})
要是想要一个新的作用域怎么办,也很简单:
tranclude(scope.$parent.$new(),function(clone){})
你要是文作用域是什么东西,作用域是怎么继承的,那不是今天我们要讲的话题。
说了这么多,这么直白,想必你已经对AngularJS的transclusion彻底的清楚明白了吧。要是不明白,再看几遍,总会明白的!!!
总结