理解Angularjs的指令

来源:互联网 发布:赛诺数据和gfk 编辑:程序博客网 时间:2024/05/22 04:34

最近撸了一遍Reactjs,然后回过头来复习Angularjs,温故而知新,为师矣就算了,但是有提高确实是实实在在的。

Angularjs的三大特征,MVC,依赖注入,指令,其中,指令是最难学的,我个人也是理解了好久。

下面,我们尝试定义一个简单的指令:

var app = angular.module("dirModule", []);app.directive("btnDanger", ["$rootScope", function($rootScope) {    return {        "restrict": "EA",        "replace": true,        "template": "<button type=\"button\">按钮</button>",        "link": function(scope, element, attr) {            element.addClass("btn").addClass("btn-danger");        }    }}])

其中,restrict是自定义指令的使用方式,E代表元素的方式,A代表属性方式,M代表注释的方式,C代表class的方式,其中,E,A最常使用,M,C不推荐,如果嫌弃麻烦,直接写“ECMA”。

使用方法如下(我只列出两种常见的):

<btn-danger></btn-danger>
<span btn-danger></span>

reaplace代表是否替换标签的内容 就以这个指令来说,假如<div btn-danger></div> 如果replace为true,生成的标签就是<button type=\"button\"></button>

这儿有一个指令叫ng-transclude,就是指令在使用的时候,假如<div btn-danger><span>我是一些测试的文本</span</div>,如果没有ng-transclude这个指令,div里面的内容就被替换掉了,于是 可以稍稍的修改一下模板代码

<button type="button"><div ng-transclude></div></button>,这样,模板里面的内容就不会被替换掉了,对于组件的组合情况,非常实用。

link是最重要的一个参数(此外还有一个compile函数,但是大漠穷秋老师说如果定义了它会改变指令默认的compile函数,一般不要考虑。),接受一个函数,参数分别是scope对象,scope对象如果没有使用独立scope的情况下,是和当前的控制器共享同一个scope(实际开发中,会使用独立scope),element就是目标元素,attr就是目标元素上的属性,如果我们属性上挂载的是一个当前控制器上的事件,可以通过attr直接获得并执行之,但是一定要用scope.$apply(attr.***)去执行,这样是为了让函数的执行效果影响到scope上面的数据,视图才会得到相应的更新(参考$apply,$digest),Angularjs的设计思想是建议不要在控制器里面操作DOM,而我们操作DOM的时机就是在link函数里(element是一个已经被jquery包裹后的对象,Angularjs内置了一个精简版的jquery,可以进行jquery的一系列操作,可以console打印出来看一下)。

下面来一个更复杂的指令:

app.directive("myButton", ["$rootScope", function($rootScope) {    return {        "scope": {            "innerHtml": "@",            "selfHover": "&",            "selfOut": "&"        },        "restrict": "EA",        "replace": true,        "template": "<button type=\"button\"  ng-bind=\"innerHtml\"></button>",        "link": function(scope, element, attr) {            element.addClass("btn").addClass("btn-danger");            element.bind("mouseover", function() {                scope.$apply(scope.selfHover);            });            element.on("mouseout", function() {                scope.$apply(scope.selfOut);            });        }    }}]);


先贴出controller的代码,然后再详细阐述:

var app = angular.module("ctrlModule", ["dirModule", "serviceModule"]);app.controller("baseController", ["$rootScope", "$scope", function($rootScope, $scope) {    $scope.data = {        name: "yangxu",        age: "22"    };    $scope.eventClick = function() {        alert("click");    };    $scope.eventHandler = function() {        $scope.data = {            name: "lijiayu",            age: 21        };    };    $scope.eventOut = function() {        $scope.data = {            name: "yangxu",            age: "22"        };    }}]);

html:

  <my-button inner-html='{{data.name}}' self-hover="eventHandler()" self-out="eventOut()"></my-button>

本文的第一个指令并没有使用独立scope,当指令修改了scope的数据以后,如果共享一个scope,就像多线程争抢的时候,大家都操作一个东西,肯定会出问题,于是出现了独立scope(独立scope,我个人的理解就是指令作用域上的scope)。

scope有3种绑定形式,"&","=","@",其中@绑定是字符串绑定,大漠穷秋老师讲的比较复杂,我个人的理解就是把挂载有当前指令上的属性,挂载到当前指令所属scope上,这个针对字符串进行绑定(我个人的理解就是一种单向绑定)。“=”是对象绑定,简单的理解就是双向数据绑定。假设现在挂着有当前指令的元素的某个属性是来自当前控制器ng-model的一个值。这个值传递到指令内部以后,指令修改它以后,还会影响到当前控制器的这个值。“&”,主要是针对函数。假如使用了独立scope,举例子来说吧,在上述代码中,selfHover代表的就是父控制器的中绑定的函数,然后在link函数中,我们就不能直接使用scope.$apply(attr.selfHover)执行方法了,因为使用隔离的scope,将拿不到父控制器中的方法,而是使用scope.$apply(scope.selfHover);

虽然Angularjs适合开发一些大型单页面应用程序,但是对于多页面的应用程序,如果我们把一些公用的代码抽到指令里面去(如何模块化组织Angularjs代码可以参考我的;另一篇日志),在需要的地方注入,可以编写出维护性良好的Web应用程序。


注意:

1.自定义属性避免使用data-开头的属性。

2.指令如果以元素形式使用的话,那么,一定要使用<directive></directive>这样的形式,避免使用<directive />这种形式。

3.独立scope上绑定的字段,在使用指令的时候,尽量符合驼峰命名法的规范,然后目标元素上面书写的时候必须符合"x-x"这样的形式,比如ngClick,这个指令,在html元素上就使用的是ng-click 


以上内容参考自imooc大漠穷秋老师所讲授的内容,有参考了金旭亮老师的Angularjs讲解,http://mooc.study.163.com/course/BIT-1000013000#/info,向他们致谢。





0 0