angular自定义指令命名的那个坑
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,翻译过来叫'嵌入',感觉还是有些生涩。template
和scope
已经可以做很多事情了,但有一点不足。
比如在原有元素的基础上添加内容,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() {
return {
restrict: 'A',
template: '<p>{{ myController.name }}</p>',
controllerAs: 'myController',
controller: function() {
this.name = "Kavlez"
}
};
});
compile (Object/Function)
虽说这个东西不是很常用吧,但却是值得了解的选项。compile
和link
,这两个选项关系到AngularJS的生命周期。
先在这里简单记录一下我对生命周期的认识。
- 应用启动前,所有的指令以文本的形式存在。
- 应用启动后便开始进行compile和link,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>
angular自定义指令命名的那个坑的更多相关文章
- angular 自定义指令详解 Directive
在angular中,Directive,自定义指令的学习,可以更好的理解angular指令的原理,当angular的指令不能满足你的需求的时候,嘿嘿,你就可以来看看这篇文章,自定义自己的指令,可以满足 ...
- Angular自定义指令(directive)
angular自定义指令,意我们可以通过angula自己定义指令,来实现我们的特殊要求,为所欲为,一支穿云箭,千军万马来相见 多少年的老规矩了,先看代码: <!DOCTYPE html> ...
- Angular自定义指令directive:scope属性
在AngularJS中,除了内置指令如ng-click等,我们还可以自定义指令.自定义指令,是为了扩展DOM元素的功能.代码中,通过指定directive中的restrict属性,来决定这个指令是作为 ...
- angular自定义指令
1.在directive文件下创建指令的js文件 通常自定义指令需要声明模块(注意定义指令时, js内部指令名称需采用 aaAaBb驼峰的命名方式 html中使用的是aa-aa-bb) e.g (f ...
- angular 自定义指令 directive transclude 理解
项目中断断续续的用了下angular,也没狠下心 认真的学习.angular 特别是自定义指令这块 空白. transclude 定义是否将当前元素的内容转移到模板中.看解释有点抽象. 看解释有点抽象 ...
- Angular17 Angular自定义指令
1 什么是HTML HTML文档就是一个纯文本文件,该文件包含了HTML元素.CSS样式以及JavaScript代码:HTML元素是由标签呈现,浏览器会为每个标签创建带有属性的DOM对象,浏览器通过渲 ...
- angular -- 自定义指令和模板
angular 可以自定义一些指令,来简化我们前端的工作量. 第一种:简单指令示例: <h3>自定义指令</h3> <sheng></sheng> &l ...
- angular自定义指令相关知识及代码
原文地址 https://www.jianshu.com/p/0c015862156d 大纲 1.自定义指令之——属性指令 2.自定义属性指令的运行原理 3.自定义属性指令代码实践 4.自定义结构指令 ...
- angular自定义指令 repeat 循环结束事件;limitTo限制循环长度、限定开始位置
1.获取repeat循环结束: 自定义指令: .directive('repeatFinish', function () { return { link: function (scope, elem ...
随机推荐
- 利用PHPExcel导出Excel相关设置
功能包括: 1.设置单元格格式,包括单元格边框.单元格高度.单元格宽度 2.合并指定的单元格 3.设置Excel数据源,并将数据源保护起来(这个是为了实现单元格下拉选项功能) 4.设置字体样式 pub ...
- MySQL(五)之DDL(数据定义语言)与六大约束
前言 前面在数据库的讲解中,其实很多东西都非常的细节,在以前的学习过程中我都是没有注意到的.可能在以后的工作中会碰到所以都是做了记录的. 接下来,我将分享的是MySQL的DDL用来对数据库及表进行操作 ...
- SQL Server 2008 收缩日志(log)文件
USE TestDB; GO ALTER DATABASE TestDB SET RECOVERY SIMPLE; --设置简单恢复模式 GO ); GO ALTER DATABASE TestDB ...
- 【Raspberry Pi】openwrt 路由
http://blog.sina.com.cn/s/blog_40983e5e0102v6qt.html
- AssetBundle中Unload()方法的作用
AssetBundle.Unload(false)的作用: 官网的解释是这样的: When unloadAllLoadedObjects is false, compressed file data ...
- js正则表达式的基本语法
1.正则表达式基本语法 创建正则表达式 var re = new RegExp();//RegExp是一个对象,和Aarray一样 //但这样没有任何效果,需要将正则表达式的内容作为字符串传递进去 r ...
- 使用 MVVMLight 消息通知
欢迎阅读我的MVVMLight教程系列文章<关于 MVVMLight 设计模式系列> 在文章的其实我们就说了,MVVMLight的精华就是消息通知机制,设计的非常不错.这个东西在MVVML ...
- Objective-c官方文档翻译 类的定义
类是对象的蓝图. 一个类是描述了对象的行为和属性.例如NSString的一个实例.他的类提供了各种的方法来转化和表示他的内部字符的表示. 每个类的实例都包含了这个类的属性和行为.例如每个NSSt ...
- 如何理解精通PHP ?
「精通 PHP」可以理解为以下三个: 精通「PHP 解析器 精通「PHP 语法.函数(这门语言) 精通「PHP 项目开发 1 精通「PHP 解析器」 可以从这里开始学习: PHP核心:骇客指南 :ht ...
- 有道云笔记同步IT笔试面试资源
有道云笔记同步资源 放在手机上ipad或者电脑上看..特别方便...精心整理..暂时只有c++的..希望大家喜欢 暂时只扒了一些c++的..java的随后扒 主要都是取自<程序员面试笔试宝典&g ...