自定义HTML元素和属性
可以把它简单的理解成在特定DOM元素上运行的函数,指令可以扩展这个元素
的功能。
angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: 'E',
replace: true,
template: 'Click me to go to Google'
};
});
四种使用方式
<my-directive>my-directive>
<div my-directive>div>
<div class="my-directive">div>
在指令中设置相应的属性
template: '<a href="{{ myUrl }}">{{ myLinkText }}a>'
在元素中传入相应 的属性值
<div my-directive
my-url="http://google.com"
my-link-text="Click me to go to Google">
div>
如果控制器被移除,或者在控制器的作用域中也
定义了一个叫myUrl的属性,我们就被迫要修改代码,这是成本很高且让人沮丧的事情。
scope: {
someProperty: "needs to be set"
}
创建了一个隔离作用域,该scope中的的属性,只能在指令 的方法或指令的模板字符串中使用
scope: {
someProperty: '@'
}
//对应 的属性值
<div my-directive
some-property="someProperty with @ binding">
div>
名称不一样的情况
scope: {
someProperty: '@someAttr'
}
//对应 的是some-attr,而不是som-property
<div my-directive
some-attr="someProperty with @ binding">
div>
ng-开头
angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: String,
priority: Number,
terminal: Boolean,
template: String or Template Function: function(tElement, tAttrs)(...
},
templateUrl: String,
replace: Boolean or String,
scope: Boolean or Object,
transclude: Boolean,
controller: String or
function(scope, element, attrs, transclude, otherInjectables) {... },
controllerAs: String,
require: String,
link: function(scope, iElement, iAttrs) {... },
compile: // 返回一个对象或连接函数,如下所示:
function(tElement, tAttrs, transclude) {
return {
pre: function(scope, iElement, iAttrs, controller) {... },
post: function(scope, iElement, iAttrs, controller) {... }
}
// 或者
return function postLink(...) {... }
}
};
});
restrict是一个可选的参数。它告诉AngularJS这个指令在DOM中可以何种形式被声明。默
认AngularJS认为restrict的值是A,即以属性的形式来进行声明
E(元素)
<my-directive>my-directive>
A(属性,默认值)
<div my-directive="expression">div>
C(类名)
<div class="my-directive:expression;">div>
M(注释)
<--directive:my-directive expression-->
这些选项可以单独使用,也可以混合在一起使用
angular.module('myDirective', function() {
return {
restrict: 'EA' // 输入元素或属性
};
});
//调用 方式
<-- 作为一个属性 -->
<-- 或者作为一个元素 -->
<my-clock>my-clock>
<my-clock clock-display="analog"></my-clock>
对my-clock的扩展
- 标准: 定义的指令是否包含某个组件的核心行为,或者用额外的行为、状态或者其他内容(比如模拟时钟)对某个核心组件进行修饰或扩展
- 另外一个重要的标准,是根据指令是否创建、继承或将自己从所属的环境中隔离出去进行判断。
可选 ,默认值 是0, 值越高,优先级越高,会比其他指令 先调用
如果一个元素上,有 两个相同 优先级的指令 ,声明 在前面的优先调用
ngRepeat是所有内置指令中优先级最高的,1000
terminal是一个布尔型参数,可以被设置为true或false。
这个参数用来告诉AngularJS停止运行当前元素上比本指令优先级低的指令。但同当前指令
优先级相同的指令还是会被执行。
使用了terminal参数的例子是ngView和ngIf。ngIf的优先级略高于ngView,如果ngIf的表
达式值为true,ngView就可以被正常执行,但如果ngIf表达式的值为false,由于ngView的优先级较低就不会被执行。
可选,两种形式:
- 一段HTML文本;
- 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个代表模板的字符
串
tElement: 模板所在的元素
tAttrs: 模板 所在的元素的属性
template: '\
<div> <-- single root element -->\
<a href="http://google.com">Click mea>\
<h1>When using two elements, wrap them in a parent elementh1>\
div>\
可选 参数 ,两种方式
- 一个代表外部HTML文件路径的字符串;
- 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个外部HTML文件
路径的字符串。
可选参数 ,布尔型 ,默认值 是false
false: 模板会被 当作 子元素插入到调用 些指令 的元素内部
<div some-directive>div>
.directive('someDirective', function() {
return {
template: '<div>some stuff here<div>'
};
});
调用 后的样子:
<div some-directive>
<div>some stuff here<div>
div>
true:的样子,当作同级的元素
<div>some stuff here<div>
可选 ,默认是false
false: 使用父作用域,指令中对属性的修改,会直接 作用到父级作用域中
true: 从父作用域继承 ,并创建一个新的作用域对象 ,指令 中可以访问 父级的作用域,修改不会影响 到父级
{}: 创建一个隔离作用域,不能访问 父级的作用域,修改也不会影响 到父级
<input type="text" ng-model="to" />
<div scope-example ng-model="to" on-send="sendMail(email)" from-name="[email protected]" />
scope: {
ngModel: '=', // 将ngModel同指定对象绑定
onSend: '&', // 将引用传递给这个方法
fromName: '@' // 储存与fromName相关联的字符串
}
可选参数 ,默认值 是false,决定 元素下的html代码 是否嵌入到模板 中
只有当你希望创建一个可以包含任意内容的指令时,才使用transclude: true。
<div sidebox title="Links">
<ul>
<li>First linkli>
<li>Second linkli>
ul>
div>
angular.module('myApp', [])
.directive('sidebox', function() {
return {
restrict: 'EA',
scope: {
title: '@'
},
transclude: true,
template: '<div class="sidebox">\
<div class="content">\
<h2 class="header">{{ title }}h2>\
<span class="content" ng-transclude>\
span>\
div>\
div>'
};
});
嵌入 的位置 是 ng-transclude标签片,
- 不足:
如果指令使用了transclude参数,那么在控制器(下面马上会介绍)中就无法正常监听数
据模型的变化了。这就是最佳实践总是建议在链接函数里使用$watch服务的原因。
controller参数可以是一个字符串或一个函数
angular.module('myApp', [])
.directive('myDirective', function() {
restrict: 'A', // 始终需要
controller: 'SomeController'
})
// 应用中其他的地方,可以是同一个文件或被index.html包含的另一个文件
angular.module('myApp')
.controller('SomeController', function($scope, $element, $attrs, $transclude) {
// 控制器逻辑放在这里
});
可以在指令内部通过匿名构造函数的方式来定义一个内联的控制器
angular.module('myApp', [])
.directive('myDirective', function() {
restrict: 'A',
controller: function($scope, $element, $attrs, $transclude) {
// 控制器逻辑放在这里
}
});
参数说明 :
- scope与指令元素相关联的当前作用域。− element 当前指令对应的元素。
- $attrs 由当前元素的属性组成的对象。例如,下面的元素:
<div id="aDiv"class="box">div>
$attrs接收到的值 如下 :
{
id: "aDiv",
class: "box"
}
angular.module('myApp')
.directive('link', function() {
return {
restrict: 'EA',
transclude: true,
controller: function($scope, $element, $transclude, $log) {
$transclude(function(clone) {
var a = angular.element('');
a.attr('href', clone.text());
a.text(clone.text());
$log.info("Created new a tag in link directive");
$element.append(a);
});
}
};
});
clone 参数 是什么?
与link的差别:
指令的控制器和link函数可以进行互换。控制器主要是用来提供可在指令间复用的行为,但链接函数只能在当前内部指令中定义行为,且无法在指令间复用。
link函数可以将指令互相隔离开来,而controller则定义可复用的行为。
如果我们希望将当前指令的API暴露给其他指令使用,可以使用controller参数,否则可以
使用link来构造当前指令元素的功能性。
如果我们使用了scope.$watch()或者想要与DOM元素做实时的交互,使用链接会是更好的选择。
controllerAs参数用来设置控制器的别名,可以以此为名来发布控制器
作用:
在路由和指令中创建匿名控制器的强大
能力。这种能力可以将动态的对象创建成为控制器,并且这个对象是隔离的、易于测试的。
加载 其他 指令 的控制器
作为当前 指令 链接 函数 的第四个 参数
修饰:
- ?:如果在当前指令中没有找到所需要的控制器,会将null作为传给link函数的第四个参数
- ^:如果添加了^前缀,指令会在上游的指令链中查找require参数所指定的控制器。
- ?^:将前面两个选项的行为组合起来,我们可选择地加载需要的指令并在父指令链中进行查找。
- 没有前缀:如果没有前缀,指令将会在自身所提供的控制器中进行查找,如果没有找到任何控制器(或具有指定名字的指令)就抛出一个错误。
例子:ng-repeat 它会遍历指定的数组或对象,在数据绑定之前构建出对应的DOM结构。
一个指令一旦编译完成,马上就可以通过编译函数对其进行访问,编译函数的签名包含有访问指令声明所在的元素(tElemente)及该元素其他属性(tAttrs)的方法。这个编译函
数返回前面提到的模板函数,其中含有完整的解析树。
由于每个指令都可以有自己的模板和编译函数,每个模板返回的也都是自己
的模板函数。链条顶部的指令会将内部子指令的模板合并在一起成为一个模板函数并返回,但在树的内部,只能通过模板函数访问其所处的分支。
最后,模板函数被传递给编译后的DOM树中每个指令定义规则中指定的链接函数
用link函数创建可以操作DOM的指令。
作用:负责设置事件监听器,监视数据变化和实时的操作DOM。
参数:
// require 'SomeController',
link: function(scope, element, attrs, SomeController) {
// 在这里操作DOM,可以访问required指定的控制器
}