这一篇从自定义指令出发,记录了定义一个指令时影响指令行为的各种因素。

试着感受这些因素,让自己更高效地编写AngularJS应用。

Directive

先从定义一个简单的指令开始。
定义一个指令本质上是在HTML中通过元素、属性、类或注释来添加功能。

AngularJS的内置指令都是以ng开头,如果想自定义指令,建议自定义一个前缀代表自己的命名空间。

这里我们先使用my作为前缀:

var myApp = angular.module('myApp', []).directive('myDirective', function() {return {restrict: 'A',replace: true,template: '<p>Kavlez</p>'};
})

如此一来,我们可以这样使用,注意命名是camel-case:

<my-directive />
<!-- <my-directive><p>Kavlez</p></my-directive> -->

directive()接受两个参数

  • name:字符串,指令的名字
  • factory_function:函数,指令的行为

应用启动时,以name作为该应用的标识注册factory_function返回的对象。

在factory_function中,我们可以设置一些选项来改变指令的行为。

下面记录一下定义指令时用到的选项

restrict (string)

该属性用于定义指令以什么形式被使用,这是一个可选参数,本文开头定义的指令用的也是A,其实该选项默认为A。

也就是元素(E)、属性(A)、类(C)、注释(M)

(ps:EMAC? EMACS? 挺好记哈)

比如上面定义的myDirective,可以以任何形式调用。

  • E(元素)
    <my-directive></my-directive>
  • A(属性,默认值)
    <div my-directive="expression"></div>
  • C(类名)
    <div class="my-directive:expression;"></div>
  • M(注释)
    <--directive:my-directive expression-->

priority (Number)

也就是优先级,默认为0。

在同一元素上声明了多个指令时,根据优先级决定哪个先被调用。

如果priority相同,则按声明顺序调用。

另外,no-repeat是所有内置指令中优先级最高的。

terminal (Boolean)

终端? 而且还是Boolean?

被名字吓到了,其实terminal的意思是是否停止当前元素上比该指令优先级低的指令
但是相同的优先级还是会执行。

比如,我们在my-directive的基础上再加一个指令:

.directive('momDirective',function($rootScope){return{priority:3,terminal:true};
})

调用发现my-directive不会生效:

<div mom-directive my-directive="content" ></div>

template (String/Function)

至少得输出点什么吧? 但template也是可选的。

String类型时,template可以是一段HTML。

Function类型时,template是一个接受两个参数的函数,分别为:

  • tElement
  • tAttrs

函数返回一段字符串作为模板。

templateUrl (String/Function)

这个就和上面的template很像了,只不过这次是通过URL请求一个模板。
String类型时,templateURL自然是一个URL。
Function类型时返回一段字符串作为模板URL。

replace (Boolean/String)

默认值为false,以文章开头定义的指令为例,假设我们这样调用了指令

<my-directive></my-directive>

replace为true时,输出:

<p>Kavlez</p>

replace为false时,输出:

<my-directive><p>Kavlez</p></my-directive>

transclude (Boolean)

该选项默认为false,翻译过来叫'嵌入',感觉还是有些生涩。

templatescope已经可以做很多事情了,但有一点不足。

比如在原有元素的基础上添加内容,transclude的例子如下:

<body ng-app="myApp"><textarea ng-model="content"></textarea><div my-directive title="Kavlez"><hr>{{content}}</div>
</body>
<script type="text/javascript">
var myApp = angular.module('myApp', [])
.directive('myDirective', function() {return {restrict: 'EA',scope: {title: '@',content: '='},transclude: true,template: '<h2 class="header">{{ title }}</h2>\<span class="content" ng-transclude></span>'};
});
</script>

发现div下的hr并没有被移除,就是这样的效果。

注意不要忘了在模板中声明ng-transclude

scope (Boolean/Object)

默认为false,true时会从父作用域继承并创建一个自己的作用域。

ng-controller的作用也是从父作用域继承并创建一个新的作用域。

比如这样,离开了自己的作用域就被打回原形了:

<div ng-init="content='from root'">{{content}}<div ng-controller="AncestorController">{{content}}     <div ng-controller="ChildController">{{content}}     </div>{{content}} </div>{{content}}
</div>.controller('ChildController', function($scope) {$scope.content = 'from child';
})
.controller('AncestorController', function($scope) {$scope.content = 'from ancestor';
})

但不要误解,指令嵌套并不一定会改变它的作用域。

既然true时会从父作用域继承并创建一个自己的作用域,那么我们来试试改为false会是什么样子:

<div ng-init="myProperty='test'">{{ myProperty }}<div my-directive ng-init="myProperty = 'by my-directive'">{{ myProperty }}</div>{{ myProperty }}
</div>.directive('myDirective', function($rootScope) {return {scope:false};
})

显然,结果是三行'by my-directive'。

非true即false? naive!

其实最麻烦的还是隔离作用域

我们稍微改动一下myDirective,改为输出<p>{{内容}}</p>

于是我试着这样定义:

<body ng-app="myApp" ><p ng-controller="myController"><div my-directive="I have to leave." ></div>{{myDirective}}</p>
</body>
<script type="text/javascript">
var myApp = angular.module('myApp', [])
.directive('myDirective', function($rootScope) {$rootScope.myDirective = 'from rootScope';return {priority:1000,restrict: 'A',replace: true,scope: {myDirective: '@',},template: '<p>{{myDirective}}</p>'};
})
.controller('myController',function($scope){$scope.myDirective = 'from controller';
});
</script>

这里需要注意的不是@,重点是隔离作用域

根据上面的例子输出,template中的{{myDirective}}不会影响到其他作用域。

我们再试试这样:

<input type="text" ng-model="content">
<p ng-controller="myController" >
<div my-directive="{{content}}" ></div>{{content}}
</p>

发现大家都在一起变,也就是说值是通过复制DOM属性并传递到隔离作用域。

ng-model是个强大的指令,它将自己的隔离作用域和DOM作用域连在一起,这样就是一个双向数据绑定。

如何向指令的隔离作用域中传递数据,这里用了@

或者也可以写成@myDirective,也就是说换个名字什么的也可以,比如我用@myCafe什么的给myDirective赋值也是没问题的,总之是和DOM属性进行绑定。

另外,我们也可以用=进行双向绑定,将本地作用域的属性同父级作用域的属性进行双向绑定

比如下面的例子中,隔离作用域里的内容只能是'abc' :

<body ng-app="myApp" ng-init="content='abc'"><p ng-controller="myController" ><input type="text" ng-model="content"><div my-directive="content" ></div>{{content}}</p>
</body>
<script type="text/javascript">
var myApp = angular.module('myApp', [])
.directive('myDirective', function($rootScope) {return {priority:1000,restrict: 'A',replace: true,scope: {myDirective: '=',},template: '<p>from myDirective:{{myDirective}}</p>'};
})
.controller('myController',function($scope){$scope.content = 'from controller';
});
</script>

在隔离作用域访问指令外部的作用域的方法还有一种,就是&

我们可以使用&与父级作用域的函数进行绑定,比如下面的例子:

<body ng-app="myApp"><div ng-controller="myController"><table border='1'><tr><td>From</td><td><input type="text" ng-model="from"/></td></tr><tr><td>To</td><td><input type="text" ng-model="to"/></td></tr><tr><td>Content</td><td><textarea cols="30" rows="10" ng-model="content"></textarea></td></tr><tr><td>Preview:</td><td><div scope-example to="to" on-send="sendMail(content)" from="from" /></td></tr></table></div>
</div></body>
<script type="text/javascript">
var myApp = angular.module('myApp', [])
.controller('myController',function($scope){$scope.sendMail=function(content){console.log('content is:::'+content);}
})
.directive('scopeExample',function(){return{restrict:'EA',scope: {to: '=', from: '=' ,send: '&onSend'},template:'<div>From:{{from}}<br>\To:{{to}}<br>\<button ng-click="send()">Send</button>\</div>'}
})
</script>

controller (String/Function)

控制器也可以在指令里定义,比如:

.directive('myDirective', function() {restrict: 'A',controller: 'myController'
}).controller('myController', function($scope, $element, $attrs,$transclude) {//...
})

相同的效果,也可以这样声明:

directive('myDirective', function() {restrict: 'A',controller:function($scope, $element, $attrs, $transclude) {//...}
});

controllerAs (String)

可以从名字和类型看出,这个选项是用来设置控制器的别名的。

比如这样:

directive('myDirective', function() {restrict: 'A',controller:function($scope, $element, $attrs, $transclude) {//...}
});

compile (Object/Function)

虽说这个东西不是很常用吧,但却是值得了解的选项。

compilelink,这两个选项关系到AngularJS的生命周期。

先在这里简单记录一下我对生命周期的认识。

  • 应用启动前,所有的指令以文本的形式存在。* 应用启动后便开始进行compilelink,DOM开始变化,作用域与HTML进行绑定。* 在编译阶段,AngularJS会遍历整个HTML并处理已声明的指令。
  • 一个指令的模板中可能使用了另外一个指令,这个指令的模板中可能包含其他指令,如此层层下来便是一个模板树。* 在DOM尚未进行数据绑定时对DOM进行操作开销相对较小,这时像ng-repeat之类的指令对DOM进行操作则再合适不过了。
  • 我们可以用编译函数访问编译后的DOM,在数据绑定之前用编译函数对模板DOM进行转换,编译函数会返回模板函数。
    也就是说,设置compile函数的意义在于:在指令和实时数据被放到DOM中之前修改DOM
    此时完全可以毫无顾虑地操作DOM。
  • 接着我们便可以进入下一个阶段,链接阶段
  • 最后,模板函数传递给指令指定的链接函数,链接函数对作用域和DOM进行链接。

好了,接下来我们就试试compile:

<body ng-app="myApp"><my-directive ng-model="myName"></my-directive>
</body>
<script type="text/javascript">
var myApp = angular.module('myApp', [])
.directive('myDirective', function($rootScope) {$rootScope.myName = 'Kavlez';return {restrict: 'EA',compile:function(tEle, tAttrs, transcludeFn) {var h2 = angular.element('<h2></h2>');h2.attr('type', tAttrs.type);h2.attr('ng-model', tAttrs.ngModel);h2.html("hello {{"+tAttrs.ngModel+"}}");tEle.replaceWith(h2);}};
});
</script>

原文出处 AngularJS - 自定义指令

AngularJS - 自定义指令相关推荐

  1. AngularJS: 自定义指令与控制器数据交互

    <!doctype html> <html><head><meta charset="utf-8"><title>Ang ...

  2. AngularJS自定义指令详解(有分页插件代码)

    前言 除了 AngularJS 内置的指令外,我们还可以创建自定义指令. 通过 .directive() 函数来添加自定义的指令. 调用自定义指令时,需要在HTMl 元素上添加自定义指令名. 自定义指 ...

  3. angularJS自定义指令详解

    AngularJS指令在HTML代码中可以有四种表现形式: 1.作为一个新的HTML元素来使用. <hello></hello>或者<hello/> 2.作为一个元 ...

  4. AngularJS自定义指令–隔离范围教程

    Earlier we looked at different directive properties and created a simple directive using those prope ...

  5. AngularJS自定义指令教程第2部分

    In the previous post, we created a simple directive to manipulate the DOM's behavior. In this post, ...

  6. 带你走近AngularJS - 创建自定义指令

    带你走近AngularJS系列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自定义指令 ------------- ...

  7. AngularJS 的自定义指令

    这是一篇angularjs自定义指令的教程.就让我们来看看,如何在angularjs中自定义指令吧!我们将利用现有的guitar angularjs app,这在 教程14: AngularJ表单验证 ...

  8. angular4获得焦点事件_深究AngularJS——如何获取input的焦点(自定义指令)

    关于如何获取input框.textarea等的焦点,网上有许多文章都只是会跟你说ng-focus这个内置指令.像这种解答,只能说明作者并为真正理解人家的需求.ng-focus是一个事件,跟原生JS(J ...

  9. 深究AngularJS——如何获取input的焦点(自定义指令)

    1. 写在前面 关于如何获取input框.textarea等的焦点,网上有许多文章都只是会跟你说ng-focus这个内置指令.像这种解答,只能说明作者并为真正理解人家的需求.ng-focus是一个事件 ...

最新文章

  1. 让我为你介绍一个神器:Chimee,一套可扩展的 H5 视频播放器解决方案
  2. Java 14 可能带来什么新特性?
  3. 一步一步自定义spinner
  4. Flink 状态一致性:端到端状态一致性的保证
  5. CRM Fiori:Complex note optimization design
  6. 密码学电子书_密码学中的电子密码书(ECB)
  7. (34)Gulp 构建HTML页面文件
  8. C#接口的作用(经典)
  9. 【渝粤教育】广东开放大学 学前儿童保育学 形成性考核 (40)
  10. 181223每日一句
  11. es文件浏览器访问ftp服务器,es文件浏览器如何ftp服务器
  12. 新手建站十大免费空间推荐-稳定,可用的免费空间及其使用体验
  13. Android 在一个APP内打开另一个APP
  14. springboot 根据身份证号计算性别和年龄
  15. Win10系统CLSID大全介绍
  16. 商品sku规格选择效果,没有商品的不能选中,选择顺序不影响展示结果
  17. 企业数据中心“云化”转型解决方案
  18. 好看的网站跳转页面网站源码
  19. c语言数据结构及算法实现代码,数据结构算法实现及解析―配合严蔚敏_吴伟民编著的数据结构(C语言版和C++版)(作者 高一凡)源代码...
  20. 计算机网络校园网建设设计摘要,计算机网络专业校园网建设设计.doc

热门文章

  1. 几篇JVM实战的东西
  2. matlab练习程序(图像旋转,最邻近插值)
  3. Excel基础操作(五)--图表基础
  4. SunPower携Sunverge纽约合作开发4MWh储能项目
  5. 解决QT出现XXXX.dll不能加载问题
  6. Python Set Literals
  7. This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its de 错误解决办法
  8. 消息队列软件产品大比拼
  9. ASP.NET3.5问题集
  10. 向页面中添加音乐或flash