英文地点:directive
Directive是教HTML玩一些新花招的门路。在DOM编译时期,directives婚配HTML并实行。这许可directive注册行动或许转换DOM组织。
Angular自带一组内置的directive,关于竖立Web App有很大协助。继续扩大的话,可以在HTML定义范畴特定言语(domain specific language ,DSL)。
一、在HTML中援用directives
Directive有驼峰式(camel cased)的作风的定名,如ngBind(放在属性里貌似用不了~)。但directive也可以支蛇底式的定名(snake case),须要经由历程:(冒号)、-(减号)或_(下划线)衔接。作为一个可选项,directive可以用“x-”或许“data-”作为前缀,以满足HTML考证须要。这里列出directive的正当定名:
- ng:bind
- ng-bind
- ng_bind
- x-ng-bind
- data-ng-bind
Directive可以安排于元素名、属性、class、解释中。下面是援用myDir这个directive的等价体式格局。(但许多directive都限定为“属性”的运用体式格局)
<span my-dir="exp"></span>
<span class="my-dir: exp;"></span>
<my-dir></my-dir>
<!-- directive: my-dir exp -->
Directive可以经由历程多种体式格局援用,下面列出N种等价的体式格局:
<!DOCTYPE HTML>
<html lang="zh-cn" ng-app>
<head>
<meta charset="UTF-8">
<title>invoke-directive</title>
<style type="text/css">
.ng-cloak {
display: none;
}
</style>
</head>
<body>
<div ng-controller="MyCtrl">
Hello <input ng-model="name"/><hr/>
ngBind="name" 这个用不了~~ <span ngBind="name"></span><br/>
ng:bind="name"<span ng:bind="name"></span><br/>
ng_bind="name"<span ng_bind="name"></span><br/>
ng-bind="name"<span ng-bind="name"></span><br/>
data-ng-bind="name"<span data-ng-bind="name"></span><br/>
x-ng-bind="name"<span x-ng-bind="name"></span><br/>
</div>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
function MyCtrl($scope) {
$scope.name = "beauty~~";
}
</script>
</body>
</html>
二、String interpolation
在编译历程当中,compiler经由历程$interpolate效劳婚配文本与属性中的嵌入表达式(如{{something}})。这些表达式将会注册为watches,而且作为digest cycle(之前不是digest-loop吗?!)的一部分,一同更新。下面是一个简朴的interpolation:
<img src="img/{{username}}.jpg"/>Hello {{username}}!
三、Compilation process, and directive matching
HTML“编译”的三个步骤:
1. 起首,经由历程浏览器的范例API,将HTML转换为DOM对象。这是很主要的一步。因为模版必需是可剖析(相符范例)的HTML。这里可以跟大多数的模版体系做对照,它们平常是基于字符串的,而不是基于DOM元素的。
2. 对DOM的编译(compilation)是经由历程挪用$comple()要领完成的。这个要领遍历DOM,对directive举行婚配。假如婚配胜利,那末它将与对应的DOM一同,到场到directive列表中。只需一切与指定DOM关联的directive被辨认出来,他们将依据优先级排序,并依据这个递次实行他们的compile() 函数。directive的编译函数(compile function),具有一个修正DOM组织的时机,并担任发作link() function的剖析。$compile()要领返回一个组合的linking function,是一切directive本身的compile function返回的linking function的鸠合。
3. 经由历程上一步返回的linking function,将模版与scope衔接起来。这反过来会挪用directive本身的linking function,许可它们在元素上注册一些监听器(listener),以及与scope一同竖立一些watches。如许得出的结果,是在scope与DOM之间的一个双向、立即的绑定。scope发作转变时,DOM会取得对应的响应。
var $compile = ...; // injected into your code
var scope = ...;
var html = '<div ng-bind='exp'></div>';
// Step 1: parse HTML into DOM element
var template = angular.element(html);
// Step 2: compile the template
var linkFn = $compile(template);
// Step 3: link the compiled template with the scope.
linkFn(scope);
四、Reasons behind the compile/link separation
在这个时刻,你可能会想知道为何编译历程会划分为compile和linke两个步骤。为了邃晓这一点,让我们看看一个实在的例子(repeater)
Hello {{user}}, you have these actions:
<ul>
<li ng-repeat="action in user.actions">{{action.description}}</li>
</ul>
简朴地讲,之所以离开compile和linke两步,是因为偶然刻须要在model转变后,对应的DOM组织也须要转变的状况,如repeaters。
当上面的例子被编译时,编译器会遍历一切节点以寻觅directive。{{user}}是一个interpolation directive的例子。ngRepeat又是别的一个directive。但ngRepeat有一个难点。它须要可以很快地为每个在users.actions中的action制作出新的li的才能。这意味着它为了满足克隆li而且嵌入特定的action(这里是指user的actions的个中一个值)的目标,须要坚持一个清洁li元素的拷贝,li元素须要被克隆和插进去ul元素。但仅仅克隆li元素是不够的。还须要编译li,以便它的directive({{action.descriptions}})可以在准确的scope中被剖析。原始的要领,平常会简朴地插进去一个li元素的拷贝,然后编译它。但编译每个li元素的拷贝会比较迟缓,因为编译历程须要我们遍历DOM节点树,查找directive并运转它们。假如我们有一个编译,须要经由历程repeater对100个item举行处置惩罚,那末我们将堕入机能题目。
题目的处理方案,是将编译历程分解为两个步骤。compile阶段辨认出一切directive,而且将它们依据优先级举行排序,在linking阶段将特定的scope与特定的li绑定在一同。
ngRepeat将各个li离开编译以防备编译历程落入li元素中。li元素的编译结果是一个包含一切包含在li元素中的directive的linking function,预备与特定li元素的拷贝举行衔接。在运转时,ngRepeat监测表达式,并作为一个item,被到场到一个li元素拷贝的数组,为克隆好的li元素建立新的scope,并挪用该拷贝对应的link function。
总结:
编译函数(compile function) – 编译函数在directive中是比较少见的,因为大多数directive只体贴与指定的DOM元素事变,而不是转变DOM元素的模版(DOM本身以及内部的组织)。为了优化机能,一些可以被directive实例同享的操纵,可以移动到compile函数中。
衔接函数(link function) – 少少directive是没有link function的。link function许可directive在指定的拷贝后的DOM元素实例上注册监听器,也可以将scope中特定内容复制到DOM中。
五、写一个directive(简易版)
在这个例子内里,我们将竖立一个依据输入花样,显现当前时候的directive。
<!DOCTYPE HTML>
<html lang="zh-cn" ng-app="TimeFormat">
<head>
<meta charset="UTF-8">
<title>time-format</title>
</head>
<body>
<div ng-controller="MyCtrl" id="main">
Date format: <input ng-model="format" type="text"/><hr/>
<!--下面运用属性x-current-time,是为了尝尝上面说的正当定名~~current:time、current-time、current_time、data-current-time -_-!!! -->
Current time is : <span x-current-time="format" id="myFormat"></span><br/>
<button ng-click="remove()">remove the span</button>
</div>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
angular.module("TimeFormat", [])
//在TimeFormat运用中注册“currentTime”这个directive的工场要领
//前文提到过,依靠注入,可以直接在function的参数中写入,这里注入了$timeout、dataFilter
.directive("currentTime", function (dateFilter) {
//这个是上面提到的linking function。(不须要增加compile function,为啥?。。。)
return function (scope, element, attr) {
var intervalId;
//更新对应element的text值,即更新时候
function updateTime() {
element.text(dateFilter(new Date(), scope.format));
}
//经由历程watch,监控span对象的currentTime的值(是format这个model值,即input的值!!)
//这个要领仅仅在format发作转变的时刻实行
scope.$watch(attr.currentTime, function (value) {
scope.format = value;
updateTime();
});
//当span被去掉的时刻,作废更新
element.bind("$destroy", function () {
clearInterval(intervalId);
});
intervalId = setInterval(updateTime, 1000);
};
}).controller("MyCtrl",function($scope,$rootScope) {
$scope.format = "M/d/yy h:mm:ss a";
$scope.remove = function() {
var oFormat = document.getElementById("myFormat");
if(oFormat) {
angular.element(oFormat).remove();//经由历程这类体式格局挪用remove,可以触发$destroy事宜啊!!!试了我N久。。。
}
};
});
</script>
</body>
</html>
六、写一个directive(细致版)
下面是一个建立directive样例(directive对象定义模版)。想看细致列表,请继续往下看。
var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
priority: 0,
template: '<div></div>',
templateUrl: 'directive.html',
replace: false,
transclude: false,
restrict: 'A',
scope: false,
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
post: function postLink(scope, iElement, iAttrs, controller) { ... }
}
},
link: function postLink(scope, iElement, iAttrs) { ... }
};
return directiveDefinitionObject;
});
在大多数场景下,我们并不须要准确掌握,所以上面的定义是可以化简的。定义模版中的每一部分,将在下面章节解说。在这个章节,我们仅仅关注定义模版的异构体(isomers of this skeleton,没看懂。。。期待人人补充)。
简化代码的第一步是依靠默许值。因而,上面的代码可以简化为:
var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
compile: function compile(tElement, tAttrs) {
return function postLink(scope, iElement, iAttrs) { ... }
}
};
return directiveDefinitionObject;
});
大多数directive只体贴实例,而不是模版转换,所以可以进一步化简(翻译得很委曲。。。期待人人补充):
var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
return function postLink(scope, iElement, iAttrs) { ... }
});
七、工场要领
工场要领担任建立directive。它仅仅运用一次,就在compiler第一次婚配到directive的时刻。你可以在这里实行一些初始化操纵。工场要领经由历程$injector.invoke实行,让它恪守一切注入声明划定规矩(rules of injection annotation),让其变成可注入的。
八、directive定义对象申明
directive定义对象供应了compiler的组织。属性以下:
name – 当前scope的称号,注册时可以运用默许值(不填)。
priority(优先级)- 当有多个directive定义在同一个DOM元素时,偶然须要明白它们的实行递次。这属性用于在directive的compile function挪用之前举行排序。假如优先级雷同,则实行递次是不确定的(经开端试验,优先级高的先实行,同级时依据相似栈的“后绑定先实行”。别的,测试时有点不小心,在定义directive的时刻,两次定义了一个雷同称号的directive,但实行结果发明,两个compile或许link function都邑实行)。
terminal(末了一组)- 假如设置为”true”,则示意当前的priority将会成为末了一组实行的directive。任何directive与当前的优先级雷同的话,他们依旧会实行,但递次是不确定的(虽然递次不确定,但基础上与priority的递次一致。当前优先级实行终了后,更低优先级的将不会再实行)。
scope – 假如设置为:
true – 将为这个directive建立一个新的scope。假如在同一个元素中有多个directive须要新的scope的话,它照样只会建立一个scope。新的作用域划定规矩不适用于根模版(root of the template),因而根模版往往会取得一个新的scope。
{}(object hash) – 将建立一个新的、自力(isolate)的scope。”isolate” scope与平常的scope的区分在于它不是经由历程原型继续于父scope的。这关于建立可复用的组件是很有协助的,可以有用防备读取或许修正父级scope的数据。这个自力的scope会建立一个具有一组泉源于父scope的当地scope属性(local scope properties)的object hash。这些local properties关于为模版建立值的别号很有协助(useful for aliasing values for templates –-!)。当地的定义是对其泉源的一组当地scope property的hash映照(Locals definition is a hash of local scope property to its source #&)$&@#)($&@#):
@或@attr – 竖立一个local scope property到DOM属性的绑定。因为属性值老是String范例,所以这个值老是返回一个字符串。假如没有经由历程@attr指定属性称号,那末当地称号将与DOM属性的称号一向。比方 ,widget的scope定义为:{localName:’@myAttr’}。那末,widget scope property的localName会映照出”hello {{name}}”转换后的实在值。name属性值转变后,widget scope的localName属性也会响应地转变(仅仅单向,与下面的”=”差别)。name属性是在父scope读取的(不是组件scope)
=或=expression(这里或许是attr) – 在当地scope属性与parent scope属性之间设置双向的绑定。假如没有指定attr称号,那末当地称号将与属性称号一致。比方 ,widget定义的scope为:{localModel:’=myAttr’},那末widget scope property “localName”将会映照父scope的“parentModel”。假如parentModel发作任何转变,localModel也会发作转变,反之亦然。(双向绑定)
&或&attr – 供应一个在父scope高低文中实行一个表达式的门路。假如没有指定attr的称号,那末local name将与属性称号一致。比方 ,widget的scope定义为:{localFn:’increment()’},那末isolate scope property “localFn”会指向一个包裹着increment()表达式的function。平常来说,我们愿望经由历程一个表达式,将数据从isolate scope传到parent scope中。这可以经由历程传送一个当地变量键值的映照到表达式的wrapper函数中来完成。比方,假如表达式是increment(amount),那末我们可以经由历程localFn({amount:22})的体式格局挪用localFn以指定amount的值(上面的例子真的没看懂,&跑哪去了?)。
controller – controller 组织函数。controller会在pre-linking步骤之前举行初始化,并许可其他directive经由历程指定称号的require举行同享(看下面的require属性)。这将许可directive之间互相沟通,加强互相之间的行动。controller默许注入了以下当地对象:
$scope – 与当前元素连系的scope
$element – 当前的元素
$attrs – 当前元素的属性对象
$transclude – 一个预先绑定到当前转置scope的转置linking function :function(cloneLinkingFn)。(A transclude linking function pre-bound to the correct transclusion scope)
require – 要求别的的controller,传入当前directive的linking function中。require须要传入一个directive controller的称号。假如找不到这个称号对应的controller,那末将会抛出一个error。称号可以到场以下前缀:
? – 不要抛出非常。这使这个依靠变成一个可选项。
^ – 许可查找父元素的controller
restrict – EACM的子集的字符串,它限定directive为指定的声明体式格局。假如省略的话,directive将仅仅许可经由历程属性声明:
E – 元素称号:
A – 属性名:
C – class名:
M – 解释 :
template – 假如replace 为true,则将模版内容替代当前的HTML元素,并将本来元素的属性、class一并迁徙;假如为false,则将模版元素看成当前元素的子元素处置惩罚。想相识更多的话,请检察“Creating Widgets”章节(在哪啊。。。Creating Components就有。。。)
templateUrl – 与template基础一致,但模版经由历程指定的url举行加载。因为模版加载是异步的,所以compilation、linking都邑停息,守候加载终了后再实行。
replace – 假如设置为true,那末模版将会替代当前元素,而不是作为子元素增加到当前元素中。(注:为true时,模版必需有一个根节点)
transclude – 编译元素的内容,使它可以被directive所用。须要(在模版中)合营ngTransclude运用(援用)。transclusion的长处是linking function可以取得一个预先与当前scope绑定的transclusion function。平常地,竖立一个widget,建立isolate scope,transclusion不是子级的,而是isolate scope的兄弟。这将使得widget具有私有的状况,transclusion会被绑定到父级(pre-isolate)scope中。(上面那段话没看懂。但现实试验中,假如经由历程 {{name}}</any my-directive>挪用myDirective,而transclude设置为true或许字符串且template中包含 的时刻,将会将{{name}}的编译结果插进去到sometag的内容中。假如any的内容没有被标签包裹,那末结果sometag中将会多了一个span。假如本来有其他东西包裹的话,将保持原状。但假如transclude设置为’element’的话,any的团体内容会出如今sometag中,且被p包裹)
true – 转换这个directive的内容。(这个觉得上,是直接将内容编译后搬入指定处所)
‘element’ – 转换全部元素,包含其他优先级较低的directive。(像将团体内容编译后,看成一个团体(表面再包裹p),插进去到指定处所)
compile – 这里是compile function,将在下面章节细致解说
link – 这里是link function ,将在下面章节细致解说。这个属性仅仅是在compile属性没有定义的状况下运用。
九、Compile function
function compile ( tElement, tAttrs, transclude) { … }
compile function用于处置惩罚DOM模版的转换。因为大多数directive都不须要转换模版,所以compile不会常常被运用到。须要compile function的directive,平常是那种须要转换DOM模版的(如ngRepeat),或许是须要异步加载内容的(如ngView)。compile function具有一下的参数:
tElement – 模版元素 – 运用当前directive的元素。仅仅在当前元素或许当前元素子元素下做模版转换是平安的。
tAttrs – 模版属性 – 范例化的属性,在当前元素声明的,可以在各个directive之间同享。概况请看Attributes章节
transclude – 一个转换用的linking function: function(scope,cloneLinking).
注重:假如template被克隆过,那末template实例和link实例不能是同一个object。为此,在compile function中做任何除了DOM转换之外的事变,是不平安的,这将运用到一切克隆中。特别是,DOM事宜监听器的注册的操纵,应该在linking function中举行,而不是compile function。
compile function 可以有一个返回值,范例可所以function或许object。
返回function – 通常在不须要compile function(为空)时运用,等同于经由历程link(directive定义模版的属性)注册linking function。
返回包含pre、post属性的object – 许可我们掌握在linking phase时期什么时候挪用linking function。概况请看下面关于pre-linking、post-linking function的章节。
十、Linking function
function link( scope, iElement, iAttrs, controller) { … }
link function担任注册DOM事宜监听器,也可以举行DOM的更新操纵。link function会在模版克隆操纵终了以后实行。这里存放着directive大多数的逻辑。
- scope – Scope – 被directive用于注册watches(http://docs.angularjs.org/api/ng.$rootScope.Scope#$watch)。
- iElement – 元素实例 – directive运用的元素。只要在postLink function内里对子元素举行操纵,才是平安的。因为子元素已被link(与model衔接吗?!)。
- iAttrs – 属性实例 – 范例的当前元素的属性列表。在一切directive的linking function之间分享的。
- controller – controller实例 – 假如在当前元素的directive中,有个中一个定义了controller,那末可以在这里猎取到该controller的实例。这个controller是在一切directive之间同享的,许可各个directive将controller看成一个它们之间沟通频道。
Pre-link function
在子元素linked之前实行。在这里做DOM转换是不平安的,因为compiler的linking function在link时可能会定位不到准确的元素。
Post-link function
在子元素linked以后实行。在这里实行DOM转换是平安的。
十一、Attributes
attribute object – 在link()或compile()中作为参数 – 是一个接见以下东东的门路:
- 范例化的属性称号:因为directive,比方ngBind,可以表现为多种情势,如”ng:bind”、”x-ng-bind”……这个attribute对象许可我们经由历程范例定名(驼峰式)接见属性。
- directive 之间通信:一切directive同享一个attribute对象实例,使得directive可以经由历程attribute 对象举行directive之间的内部通信。
- 支撑interpolation:interpolation属性是分配到attribute对象中,许可其他directive读取该interpolated value。
- 视察interpolated属性:经由历程attr.$observe去视察属性值的变化,包含interpolation(比方src=”{{bar}}”)。不单单很有用,而且是简朴地猎取实在值唯一的方法。因为在linking阶段,interpolation还没被赋值(替代实在值),所以在这时刻接见它,结果是undefined。
<!DOCTYPE HTML>
<html lang="zh-cn" ng-app="DirectiveProperty">
<head>
<meta charset="UTF-8">
<title>directive-attribute-test</title>
<style type="text/css">
.ng-cloak {
display: none;
}
</style>
</head>
<body ng-controller="MyCtrl">
<input type="text" ng-model="name" value="myName"/>
<p my-attr="123" directive-p2 attr-dd="{{name}}"></p>
<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
var app = angular.module("DirectiveProperty", []);
app.controller("MyCtrl", function ($scope) {
$scope.name = "my little dada";
});
var directiveP2 = app.directive("directiveP2", function () {
return {
link:function postLink(scope,lEle,lAttr) { console.log("myAttr:" + lAttr.myAttr);//123
console.log("myAttr:" + lAttr.attrDd);//undefinded
lAttr.$observe('attrDd', function(value) {
console.log('attrDd has changed value to ' + value); //my little dada
//除此之外,还可啥方法可以拿到这个值啊。。。¥&()@#&¥(@#
});
}
};
});
</script>
</body>
</html>
十二、明白transclusion和scope
我们常常须要一些可重用的组件。下面是一段伪代码,展现一个简朴的dialog组件怎样可以事变。
<
div>
<button ng-click="show=true">show</button>
<dialog title="Hello {{username}}."
visible="show"
on-cancel="show = false"
on-ok="show = false; doSomething()">
Body goes here: {{username}} is {{title}}.
</dialog>
点击“show”按钮将会翻开dialog。dialog有一个题目,与数据“username”绑定,另有一段我们想安排在dialog内部的内容。
下面是一段为了dialog而编写的模版定义:
<div ng-show="show()">
<h3>{{title}}</h3>
<div class="body" ng-transclude></div>
<div class="footer">
<button ng-click="onOk()">Save changes</button>
<button ng-click="onCancel()">Close</button>
</div>
</div>
这将没法准确衬着,除非我们对scope做一些特别处置惩罚。
第一个我们须要处理的题目是,dialog模版希冀title会被定义,而在初始化时会与username绑定。另外,按钮须要onOk、onCancel两个function出如今scope内里。这限定了插件的效能(this limits the usefulness of the widget。。。)。为相识决映照题目,经由历程以下的当地要领(locals,预计在说directive定义模版中的scope)去建立模版期待的当地变量:
scope :{
title: 'bind', // set up title to accept data-binding
onOk: 'expression', // create a delegate onOk function
onCancel: 'expression', // create a delegate onCancel function
show: 'accessor' // create a getter/setter function for visibility.
}
在控件scope中建立当地属性,带来了两个题目:
1. isolation(属性断绝?) – 假如用户忘记了在控件模版设置title这个元素属性,那末title将会与先人scope的属性”title”(若有)绑定。这是不可预知、不可取的。
2. transclusion – transcluded DOM可以检察控件的locals(isolate scope?),locals会掩盖transclusion中真正须要绑定的属性。在我们的例子中,插件中的title属性破坏了transclusion的title属性。
为相识决这个缺少属性断绝的题目,我们须要为这个directive定义一个isolated scope。isoloted scope不是经由历程从child scope(这里为啥是child scope?不是parent scope吗?)原型继续的,所以我们无需忧郁属性争执题目(作为当前scope的兄弟)。
但是,isolated scope带来了一个新题目:假如transcluded DOM 是控件的isolated scope的一个子元素,那末他将不能与任何东西绑定(if a transcluded DOM is a child of the widget isolated scope then it will not be able to bind to anything)。因而,transcluded scope是原始scope的一个子scope,在控件为当地属性而建立isolated scope之前建立的。transcluded与控件isolated scope属于兄弟节点(scope树中)。
这或许看起来会有点意想不到的庞杂,但如许做让控件用户与控件开发者最少带来了欣喜。(处理了题目)
因而,终究的directive定义大抵以下:
transclude:true,
scope :{
title: 'bind', // set up title to accept data-binding
onOk: 'expression', // create a delegate onOk function
onCancel: 'expression', // create a delegate onCancel function
show: 'accessor' // create a getter/setter function for visibility.
//我试过这么整,失利……请继续往下看
}
我尝试把上面的代码拼凑成一个完全的例子。直接复制的话,没法到达预期结果。但稍作修正后,插件可以运转了。
<!DOCTYPE html>
<html ng-app="Dialog">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>directive-dialog</title>
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<script src="../angular.js" type="text/javascript"></script>
</head>
<body>
<div ng-controller="MyCtrl">
<button ng-click="show=true">show</button>
<dialog title="Hello {{username}}"
visible="{{show}}"
on-cancel="show=false;"
on-ok="show=false;methodInParentScope();">
<!--上面的on-cancel、on-ok,是在directive的isoloate scope中经由历程&援用的。假如表达式中包含函数,那末须要将函数绑定在parent scope(当前是MyCtrl的scope)中-->
Body goes here: username:{{username}} , title:{{title}}.
<ul>
<!--这里还可以这么玩~names是parent scope的-->
<li ng-repeat="name in names">{{name}}</li>
</ul>
</dialog>
</div>
<script type="text/javascript">
var myModule = angular.module("Dialog", []);
myModule.controller("MyCtrl", function ($scope) {
$scope.names = ["name1", "name2", "name3"];
$scope.show = false;
$scope.username = "Lcllao";
$scope.title = "parent title";
$scope.methodInParentScope = function() {
alert("记着。。scope内里经由历程&定义的东东,是在父scope中玩的!!。。。");
};
});
myModule.directive('dialog', function factory() {
return {
priority:100,
template:['<div ng-show="visible">',
' <h3>{{title}}</h3>',
' <div class="body" ng-transclude></div>',
' <div class="footer">',
' <button ng-click="onOk()">OK</button>',
' <button ng-click="onCancel()">Close</button>',
' </div>',
'</div>'].join(""),
replace:false,
transclude: true,
restrict:'E',
scope:{
title:"@",//援用dialog标签title属性的值
onOk:"&",//以wrapper function情势援用dialog标签的on-ok属性的内容
onCancel:"&",//以wrapper function情势援用dialog标签的on-cancel属性的内容
visible:"@"//援用dialog标签visible属性的值
}
};
});
</script>
</body>
</html>
十三、Creating Components
我们通常会希冀经由历程庞杂的DOM组织替代掉directive(地点的元素?目标大概是使directive内部庞杂点,看起来牛点@_@)。这让directive成为运用可复用组件的竖立运用的一个快捷体式格局。
下面是一个可复用组件的例子:
<!DOCTYPE html>
<html ng-app="ZippyModule">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>ZippyModule</title>
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<style type="text/css">
.zippy {
border: 1px solid black;
display: inline-block;
width: 250px;
}
.zippy.opened > .title:before { content: '▼ '; }
.zippy.opened > .body { display: block; }
.zippy.closed > .title:before { content: '► '; }
.zippy.closed > .body { display: none; }
.zippy > .title {
background-color: black;
color: white;
padding: .1em .3em;
cursor: pointer;
}
.zippy > .body {
padding: .1em .3em;
}
</style>
<script src="../angular.js" type="text/javascript"></script>
</head>
<body>
<div ng-controller="MyCtrl">
Title: <input ng-model="title" type="text"><br/>
Text: <textarea ng-model="text" ></textarea>
<hr/>
<div class="zippy" zippy-title="Details: {{title}}...">{{text}}</div>
</div>
<script type="text/javascript">
var myModule = angular.module("ZippyModule", []);
myModule.controller("MyCtrl", function ($scope) {
$scope.title = "这里是题目";
$scope.text = "这里是内容哇。。。";
});
myModule.directive('zippy', function () {
return {
template: '<div>' +
' <div class="title">{{title}}</div>' +//这个title属于当前directive isolate scope的property
' <div class="body" ng-transclude></div>' + //这里的东西,猎取的是父scope的property咯
'</div>',
replace:true,
transclude: true,
restrict:'C',
scope:{
title:"@zippyTitle"//绑定directive元素身上的zippy-title属性
},
link:function(scope,element,attrs) {
var title = angular.element(element.children()[0]),
opened = false;
title.bind("click", toogle);
element.addClass("closed");
function toogle() {
opened = !opened;
element.removeClass(opened ? "closed" : "opened");
element.addClass(opened ? "opened" : "closed");
}
}
};
});
</script>
</body>
</html>