Angular中的内置指令跟自定义指令
NG中的指令,到底是什么(what)? 为什么会有(why)?以及怎样使用(how)?
What: 在NG中,指令扩展HTML功能,为 DOM 元素调用方法、定义行为绑定数据等。
Why: 最大程度减少DOM操作,实现数据绑定,与业务逻辑进行交互。
How: 指令主要分为两种:内置指令和自定义指令,通过下面的例子,简单记录一下如何去使用。
内置指令
在官方API文档上罗列了很多指令,内置指令可以分为:普通指令 和 事件指令,他们都是作用于HTML之上的,通过添加属性的方式来实现的。简单看一下一些常用的指令。
普通指令
-
ngApp指令
- ng-app 指令用来设定一个 AngularJS 应用程序的作用范围的根对象上
- 系统执行时会自动的执行根对象范围内的其他指令
- 可以在同一个页面创建多个 ng-app 节点(不推荐)
- 创建多个ng-app时,默认只能执行第一个,后面的需要手动引导:
angular.bootstrap()
- 标记的范围尽可能小,性能,区域范围越小,性能会更好。
-
简单示例:
html结构举例:<div ng-app='myApp'> <!--这个div是程序的最外围DIV,标识着程序的入口> </div>
对应的javascript结构:
angular.module('myApp',[]);
备注: 如果给
ng-App
赋值如:ng-app='myApp'
,那么必须要在js中初始化,如:angular.module('myApp',[])
, 不然会报错。
-
ngController指令
- 用于将控制层的一个控制器作用到视图层,用于支持MVC开发模式的重要的一个方面。
- 必须在ngApp指令的范围之内
- 这条指令创造了一个新的作用域
- 这条指令,优先级很高。
-
简单举例:
html结构:<div ng-app='myApp'> <div ng-controller='myCtrl'></div> </div>
javascript结构:
angular.module('myApp',[]) .controller('myCtrl',function(){ // your logic business });
-
ngBind指令
- 将作用域($scope)中的值绑定到元素的 innerHTML 上,其效果会比通过表达式绑定的方式更友好
- 用于改进表达式
{{}}
所带来的加载时表达式符号暂时性展现的问题。 -
简单举例:
html结构<div ng-app='myApp'> <div ng-controller='myCtrl'> <span ng-bind='username'></span> </div> </div>
javascript结构
angular.module('myApp',[]) .controller('myCtrl',['$scope',function($scope){ $scope.username='johnny'; }]);
-
ngBindHtml 指令
- 如果需要在页面上绑定 HTML 内容(比如标签的尖括号,不去转义)。
- 依赖 ngSanitize 服务,不在核心库中,需要单独引入库文件(angular-sanitize)。
-
简单示例:
html结构<div ng-app='myApp'> <div ng-controller='myCtrl'> <span ng-bind-html='htmlData'></span> </div> </div>
javascript结构
angular.module('bindHtmlExample', ['ngSanitize']) .controller('ExampleController', ['$scope', function($scope) { $scope.htmlData = 'I am an <code>HTML</code>string with ' + '<a href="#">links!</a> and other <em>stuff</em>'; }]);
-
ngRepeat 指令
- ng-repeat 指令用来遍历一个数组重复创建当前元素
- 类似于模板引擎中的each
- 官方的例子涉及的东西很多
-
举个简单的实例:
html结构<div ng-app='myApp'> <div ng-controller='myCtrl'> <ul> <li ng-repeat='item in messages track by $index' ng-bind='item'></li> </ul> </div> </div>
javascript结构
angular.module('myApp',[]) .controller('myCtrl',['$scope',function($scope){ $scope.messages =['今天下班后别走','中国队加油','今夜又失眠了','中国队加油']; }]);
上面的
track by $index
是有意义的,因为ng-repeat不能遍历重复项,为了避免程序报错,我们加上track by $index
可以在内部维护一个$index,就不会因为内容重复而报错。
-
ngClass 指令
- ng-class用来给html动态设置css样式。
- 官网上的demo很不错
-
简单自己来写一写:
css结构.red {color: red}
html结构
<div ng-app='myApp'> <div ng-controller='myCtrl'> <input type='text' placeholder='type your name' ng-model='typedName'> <div ng-repeat='item in data' ng-class='{red: typedName && item.name.startsWith(typedName)}'> <span ng-bind='item.name'></span> </div> </div> </div>
javascript结构
var data = [ { id: 1, name: '张三', age: 11, gender: 0 }, { id: 2, name: '李四', age: 12, gender: 0 }, { id: 3, name: '李丽', age: 13, gender: 1 }, { id: 4, name: '周明', age: 14, gender: 0 }, { id: 5, name: '周玥', age: 23, gender: 1 }, { id: 6, name: 'johnny', age: 24, gender: 0 } ]; angular.module('myApp', []) .controller('myCtrl', ['$scope', function($scope) { $scope.typedName = ''; $scope.data = data; }]);
上面功能实现了输入对应的名字,显示红色
- 总结一下 ng-class的用法 :
ng-class={}
,其实就是这样:ng-class={classname1:是否添加-boolean值,classname2:是否添加-boolean值}
- 另外 还有两个衍生的指令处理奇数和偶数行的样式指令: ngClassEven 和 ngClassOdd
-
ngCloak 指令
- 用于阻止html模板短暂性的展示,出现的用户体验问题
- 它会动态的在head里添加一段css样式
- 另外最重要的,angular库必须在head中引入!
- 官网上的demo,还解决了IE7css不兼容的问题。
-
下面简单写下小demo:
html结构<!-- 在header里引入包 --> <script src='http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js'></script> <!-- 在body里 --> <div ng-app='myApp'> <div ng-controller='myCtrl' ng-cloak> <div>{{user.name}}</div> <div>{{user.age}}</div> <script>alert('block!')</script> <div>{{user.gender}}</div> </div> </div>
javascript结构
angular.module('myApp', []) .controller('myCtrl', ['$scope', function($scope){ $scope.user = { 'name':'Johnny', 'age':'24', 'gender':'0' } }]);
上面的demo,如果不加ng-cloak指令,那么就会有html模板短暂性的呈现的这个bug,上面我们用了js来阻止了程序的运行,可以看到ng-cloak的作用。
-
ngShow和ngHide 指令
- 用于控制页面元素的隐藏和显示
- 值为boolean类型。
- 如果是false,就会在页面元素上加上一个类
ng-hide
用于隐藏元素 -
举个简单的例子:
html结构<!--下面是关键代码,不需要javascript结构--> 点击隐藏右侧:<input type='checkbox' ng-model='checked'> <span ng-show='!checked'>控制隐藏显示</span>
可见 ngShow 和 ngHide都是一样的,我们可以通过取非的方式只用一个就可以了。
-
ngIf 指令
- ngIf指令完全不同于ngShow或者ngHide ,它控制的是:是否有这个dom元素,而非显示隐藏。
- 举个小例子
关键代码:Click: <input type='checkbox' ng-model='checked' ng-init='checked=true' /> <span ng-if="checked">控制有还是没有</span>
-
ngSwitch 指令
- 根据表达式显示或隐藏对应的部分。
- 对应的子元素使用 ng-switch-when 指令,如果匹配选中选择显示,其他为匹配的则移除。
- 可以通过使用 ng-switch-default 指令设置默认选项,如果都没有匹配的情况,默认选项会显示。
- on 属性必须和ng-switch一起使用,或者直接使用ng-switch属性。
- 此指令优先级很高
-
官网上的小demo分析
html结构<div ng-app='myApp'> <div ng-controller='myCtrl'> <select ng-model='selection' ng-options='item for item in items'> </select> <tt>selection={{selection}}</tt> <hr/> <div ng-switch on='selection'> <div ng-switch-when='settings'>Settings Div</div> <div ng-switch-when='home'>Home Span</div> <div ng-switch-default>default</div> </div> </div> </div>
javascript结构
angular.module('myApp', []) .controller('myCtrl', ['$scope', function($scope) { $scope.items = ['settings', 'home', 'other']; $scope.selection = $scope.items[0]; }]);
- 上面用了ng-option的一个遍历循环。
- 在 ng-switch作用上的父盒子上动态的绑定了option里的值,只要选择有匹配那么在下面的子盒子就会相应的显示。其中可以使用on或者不使用on,但是ng-switch是必备的,直接用
ng-switch='selection'
也可以。
-
ngHref 和 ngSrc 指令
- ng-href / ng-src 指令用于解决当链接类型的数据绑定时造成的加载解析时的bug.因为我们的链接地址都是动态的,我们需要动态的绑定值到src或者href中,src或者href无法解析这样的形式
{{}}
所以就用 ng-src 和 ng-href来使用了。当然还有ng-srcset指令。
- ng-href / ng-src 指令用于解决当链接类型的数据绑定时造成的加载解析时的bug.因为我们的链接地址都是动态的,我们需要动态的绑定值到src或者href中,src或者href无法解析这样的形式
-
其他一些单向数据绑定的指令
- ng-checked:单选/复选是否选中,只是单向绑定数据
- ng-disabled:是否禁用
- ng-readonly:是否只读
- ng-selected:是否选中,只是单向绑定数据
事件指令
- ng-change:发生改变
- ng-copy:拷贝完成
- ng-click:单击
ng-click='func()'
- ng-dblclick:双击
- ng-focus:得到焦点
- ng-blur:失去焦点
- ng-submit:表单提交
- 等等其他事件指令,这些事件指令,在事件触发时相应的完成我们赋予的功能。
自定义指令
指令无外乎增强了 HTML,提供额外的功能
以上的指令基本上已经可以满足我们的绝大多数需要了
少数情况下我们有一些特殊的需要,可以通过自定义指令的方式实现。从更高的层次上说,指令是DOM元素上的一些标记(例如: 属性,元素名称,注释和一些CSS的类)用于转换DOM元素的内部或者对DOM元素进行一些行为上的绑定。
-
注意事项
- 自定义指令和自定义控制器都必须要挂载在模块之下。因为自定义指令的directive是angular.module下的一个方法,点击这里查看
- 具体用法为
angular.module('moduleName',[]).directive(name, directiveFactory);
-
angular.module
可以使用链式编程的形式,返回模块本身,可定义多个指令。 - 定义指令的时候用驼峰命名法如:
myDirective
, 使用的时候用匈牙利命名法:my-directive
- 自定义指令可以把一段重复使用的方法封装起来,类似封装一些组件来使用。
-
对return中的一些常用选项的说明 ,官方文档的说明(访问不了,可能是因为文档上的路由设置,需要一层层的点进去查看),就不再举例了。
- template : 用于将一段自定义的代码绑定到含有对应指令的html中。
- templateUrl : 用于将’其他html’文件渲染进入含有对应指令的html中。当然这里的’其他html’里面可以有我们的指令或者表达式,其实就是代码段,和在当前页面一样使用,只是抽离出去了,方便管理。这里会用异步请求的方式来得到这个文件。注意:此处会发送一个xhr请求。
- transclude : 值为布尔型,需要在template中添加一个内置指令ng-transclude,将含有这个自定义指令中的内容,放入到template中去渲染,然后放到含有自定义指令的DOM元素内。
- replace : 值为布尔型, 开启后就会把含有自定义指令的DOM元素,替换成template中的内容。
-
scope : 规范指令的作用域的问题,如果没写,ng中默认的是放在根作用域中的,一般每个控制器就会有一个作用域,每个指令也会存在一个作用域,并且作用域存在继承关系,我们为了规范作用域,可以在自定义指令中有一个scope选项,在scope内部定义一些属性。下面是示例代码。
html结构:<div ng-app='myApp'> <haha title='hello' data='world'></haha> </div>
javascript结构:
angular.module('myApp',[]) .directive('haha',[function(){ return { scope:{ title:'@', data:'@' }, template:'{{title}} {{data}}' } }])
代码输出 hello world 其中
@
表示 scope中的属性值,引用了使用自定义指令的DOM元素的属性值。 restrict : 用于指定自定义指令的类型。 A,表示只匹配属性。E,表示只匹配元素。C,表示只匹配类名。AEC,表示三种都可以作为匹配项。而M,匹配注释指令,已经被高版本抛弃使用了,我们推荐使用A和E。
- link函数 : angular 中允许在这个内部进行一些dom操作,格式是这样的:
link:function(scope, element, attrs){}
scope代表的是当前指令的作用域,element代表当前元素,attrs代表元素的属性,在里面用的是jqlite里面的api。备注,如果只去操作dom,那么我们只需要return一个函数就行了,不用 link选项了。
第三方依赖库指令
当然还有一些围绕angular中的第三方库比如AngularUI库里面也有无数的指令,这里就不再阐述了。
拓展知识:
- 符合W3C的自定义属性有两个 : 一个是
data-attribute
一个是x-attribute
这两个都在NG中兼容,比如ng-app
也可以写成data-ng-app
或者x-ng-app
。 - html的注入的安全问题:比如一个可以插入html内容的地方,插入了一个script标签,在脚本里面可以进行多种具有危险性的操作,比如cookie,session劫持,页面的重定向等等。解决这个问题的方式就是进行标签的转义。像这种安全问题在数据库中也存在,比如SQL注入,有机会再去学习。
更多阅读:
- http://blog.jobbole.com/62249/
- http://www.tuicool.com/articles/Z3eiQz
- http://www.runoob.com/angularjs/angularjs-expressions.html
- http://www.jb51.net/article/67946.htm
- http://www.mamicode.com/info-detail-221910.html
- http://www.html-js.com/article/1561
- http://www.tuicool.com/articles/jEvY3a
更多链接:
- http://www.cnblogs.com/powertoolsteam/p/angularjs-introdection.html
- http://www.apjs.net/
- http://www.angularjs.cn/
- http://docs.angularjs.cn/api
- https://material.angularjs.org
- http://angular-ui.github.io/