`
youyu4
  • 浏览: 440557 次
社区版块
存档分类
最新评论

AngularJS -- Directive(指令)机制

 
阅读更多

1.一点小说明

 

指令的作用:实现语义化标签

 

我们常用的HTML标签是这样的:

 

<div>
    <span>一点点内容</span>
</div>

 

而使用AngularJS的directive(指令)机制,我们可以实现这样的东西:

 

<tabpanel>
    <panel>子面板1</panel>
    <panel>子面板2</panel>
</tabpanel>

 

很多人可能要惊呼,这货和JSP或者Struts等等框架里面的taglib很像啊!

 

呃,说实话,实际上就是这样的,只不过这里是使用JavaScript来实现的。正因为如此,所以很多taglib做不到的功能,使用它就都可以做到,比如访问N层scope里面的对象之类的事情(参见后面第5个例子)。

 

2.实例1:从最简单的开始

 

<html ng-app='app'>
    <body>
        <hello></hello>
    </body>

    <script src="../angular-1.0.3/angular.min.js"></script>
    <script src="HelloDirect.js"></script>
</html>

 

对于以上代码里面的<hello>标签,浏览器显然是不认识的,它唯一能做的事情就是无视这个标签。那么,为了让浏览器能够认识这个标签,我们需要使用Angular来定义一个hello指令(本质上说就是自己来把<hello>这种玩意儿替换成浏览器能识别的那些标准HTML标签)。

 

来看这段温馨的JS代码:

 

var appModule = angular.module('app', []);
appModule.directive('hello', function() {
    return {
        restrict: 'E',
        template: '<div>Hi there</div>',
        replace: true
    };
});

 

以上代码大概看两眼就可以了,不要太在意细节。

 

然后我们就可以在浏览器里面看到这样的内容:

 



 

 

实际产生的标签结构是这样的:

 



 

 

可以看到,<hello>这个东东已经被<div>Hi there</div>这个标签替换掉了,这也是以上JS代码里面replace:true这行配置的作用,代码里面的template配置 项当然就是我们要的div标签啦,至于restrict:'E'这个配置项的含义,请看下表:

 



 

 

ok,看完上面的表格,对于restrict这个属性相信你已经秒懂了,那么我们来玩儿点花样吧。如果我们需要替换的HTML标签很长,显然不能用 拼接字符串的方式来写,这时候我们可以用templateUrl来替代template,从而可以把模板写到一个独立的HTML文件中。

 

3.实例2:transclude(变换)

 

先看例子,JS代码:

 

var appModule = angular.module('app', []);
    appModule.directive('hello', function() {
    return {
        restrict: 'E',
        template: '<div>Hi there <span ng-transclude></span></div>',
        transclude: true
    };
});

 

HTML代码:

 

<html ng-app='app'>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    </head>
    <body>
        <hello>
            <br/>
            <span>原始的内容,</span><br/>
            <span>还会在这里。</span>
        </hello>
        <hello>
        </hello>
    </body>

    <script src="../angular-1.0.3/angular.min.js"></script>
    <script src="Transclude.js"></script>
</html>

 

运行效果如下:

 



 

 

生成的HTML标签结构如下:

 



 

 

和第一个例子对比,这个例子的JS和HTML代码都略有不同,JS代码里面多了一个transclude: true,HTML代码里面在<hello>内部出现了子标签。

 

按照我们在第一个例子中的说法,指令的作用是把我们自定义的语义化标签替换成浏览器能够认识的HTML标签。那好,如果我们自定义的标签内部出现了子标签,应该如何去处理呢?很显然,transclude就是用来处理这种情况的。

 

对于当前这个例子,transclude的作用可以简化地理解成:把<hello>标签替换成我们所编写的HTML模板,但是<hello>标签内部的内容保持不变

 

很显然,由于我们没有加replace:true选项,所以<hello>标签还在,没有被替换掉。同时,通过这个例子你还还会发现一 个暗藏的属性,那就是浏览器实际上非常智能,虽然它并不认识<hello>这个标签,但是页面没有出错,它只是默默地把这个标签忽略掉了!怎 么样?是不是碉堡了?

 

你可以自己在上面的JS代码里面加上replace:true,然后再看生成的HTML结构。

 

4.实例3:关于compile和link

 

JS代码:

 

var appModule = angular.module('app', []);
appModule.directive('hello', function() {
    return {
        restrict: 'E',
        template: '<span>Hi there</span>',
        replace: true
    };
});
appModule.controller('MyController',function($scope) {
    $scope.things = [1,2,3,4,5,6];
});

 

HTML代码:

 

<html ng-app='app'>
    <body ng-controller='MyController'>
        <div ng-repeat='thing in things'>
            {{thing}}.<hello></hello>
        </div>
    </body>

    <script src="../angular-1.0.3/angular.min.js"></script>
    <script src="CompileAndLink.js"></script>
</html>

 

呃,这个例子是用来解释一点点理论的,所以单纯看效果可能看不出个鸟。

 

如前所述,指令的本质其实是一个替换过程。好,既然如此,Angular到底是如何进行替换的呢?嗯嗯,这个过程分2个阶段,也就是本节标题所说的compile(编译)和link(连接)了。

 

简而言之,compile阶段进行标签解析和变换,link阶段进行数据绑定等操作。这里面更加细节的处理过程请参见《AngularJS》这本书中的解析,这里就不赘述了(呃,实际上是因为解释起来很长很麻烦,叔懒得在这儿说了

 )。

 

那么,知道这件事情有什么用途呢?

 

比方说,你有一些事件需要绑定到某个元素上,那么你需要提供一个link函数,做法请看下一个例子。

 

5.实例4:一个复杂一点的例子Expander

 

这是《AngularJS》这本书里面提供的一个例子,但是书里面没有给出完整的可运行代码,所以这里给出来,大家参考一下。

 

JS代码:

 

var expanderModule=angular.module('expanderModule', [])
expanderModule.directive('expander', function() {
    return {
        restrict : 'EA',
        replace : true,
        transclude : true,
        scope : {
            title : '=expanderTitle'
        },
        template : '<div>'
                 + '<div class="title" ng-click="toggle()">{{title}}</div>'
                 + '<div class="body" ng-show="showMe" ng-transclude></div>'
                 + '</div>',
        link : function(scope, element, attrs) {
            scope.showMe = false;
            scope.toggle = function toggle() {
                scope.showMe = !scope.showMe;
            }
        }
    }
});
expanderModule.controller('SomeController',function($scope) {
    $scope.title = '点击展开';
    $scope.text = '这里是内部的内容。';
});

 

HTML代码:

 

<html ng-app='expanderModule'>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <script src="../angular-1.0.3/angular.min.js"></script>
        <link rel="stylesheet" type="text/css" href="ExpanderSimple.css"/>
    </head>
    <body>
        <div ng-controller='SomeController'>
            <expander class='expander' expander-title='title'>
                {{text}}
            </expander>
        </div>
    </body>
    <script src="ExpanderSimple.js"></script>
</html>

 

CSS代码:

 

.expander {
    border: 1px solid black;
    width: 250px;
}

.expander>.title {
    background-color: black;
    color: white;
    padding: .1em .3em;
    cursor: pointer;
}

.expander>.body {
    padding: .1em .3em;
}

 

运行效果如下:

 



 

 

注意一下JS代码里面的这一段:

 

link : function(scope, element, attrs) {
    scope.showMe = false;
    scope.toggle = function toggle() {
        scope.showMe = !scope.showMe;
    }
}

 

自己跑一跑例子,研究一番,不多解释。

 

6.实例5:一个综合的例子

 

JS代码:

 

var expModule=angular.module('expanderModule',[])
expModule.directive('accordion', function() {
    return {
        restrict : 'EA',
        replace : true,
        transclude : true,
        template : '<div ng-transclude></div>',
        controller : function() {
            var expanders = [];
            this.gotOpened = function(selectedExpander) {
                angular.forEach(expanders, function(expander) {
                    if (selectedExpander != expander) {
                        expander.showMe = false;
                    }
                });
            }
            this.addExpander = function(expander) {
                expanders.push(expander);
            }
        }
    }
});

expModule.directive('expander', function() {
    return {
        restrict : 'EA',
        replace : true,
        transclude : true,
        require : '^?accordion',
        scope : {
            title : '=expanderTitle'
        },
        template : '<div>'
                   + '<div class="title" ng-click="toggle()">{{title}}</div>'
                   + '<div class="body" ng-show="showMe" ng-transclude></div>'
                   + '</div>',
        link : function(scope, element, attrs, accordionController) {
            scope.showMe = false;
            accordionController.addExpander(scope);
            scope.toggle = function toggle() {
                scope.showMe = !scope.showMe;
                accordionController.gotOpened(scope);
            }
        }
    }
});

expModule.controller("SomeController",function($scope) {
    $scope.expanders = [{
        title : 'Click me to expand',
        text : 'Hi there folks, I am the content that was hidden but is now shown.'
    }, {
        title : 'Click this',
        text : 'I am even better text than you have seen previously'
    }, {
        title : 'Test',
        text : 'test'
    }];
});

 

HTML代码:

 

<html ng-app="expanderModule">
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <script src="../angular-1.0.3/angular.min.js"></script>
        <link rel="stylesheet" type="text/css" href="Accordion.css"/>
    </head>
    <body ng-controller='SomeController' >
        <accordion>
            <expander class='expander' ng-repeat='expander in expanders' expander-title='expander.title'>
                {{expander.text}}
            </expander>
        </accordion>
    </body>
    <script src="Accordion.js"></script>
</html>

 

CSS代码:

 

.expander {
    border: 1px solid black;
    width: 250px;
}

.expander>.title {
    background-color: black;
    color: white;
    padding: .1em .3em;
    cursor: pointer;
}

.expander>.body {
    padding: .1em .3em;
}

 

运行效果:

 



 

 

这个例子主要的难点在于如何在子Expander里面访问外层Accordion的scope中的数据,这一点解释起来略复杂,这里就不展开了,详细描述参见《AngularJS》一书 

分享到:
评论

相关推荐

    前端项目-angularjs-color-picker.zip

    **AngularJS Color Picker 指令** 在前端开发中,颜色选择器是一个常见的组件,用于让用户在界面上方便地选取...通过深入理解 AngularJS 的指令系统和事件处理机制,开发者可以轻松地将这个组件整合进自己的项目中。

    前端项目-tree-grid-directive.zip

    在这个名为"前端项目-tree-grid-directive.zip"的压缩包中,包含了一个使用AngularJS实现的树网格指令。AngularJS是一款强大的前端JavaScript框架,它通过声明式编程和依赖注入来简化Web应用的开发。下面将详细探讨...

    学习AngularJS-1.x.pdf

    * 数据绑定机制:AngularJS如何实现数据绑定的 五、AngularJS条件判断 * ng-if 指令:根据条件显示或隐藏元素 * ng-show 指令:根据条件显示或隐藏元素 * ng-hide 指令:根据条件隐藏元素 六、AngularJS重复语句 ...

    mastering-angularjs-directives:有关AngularJS自定义指令的示例

    - 避免在指令中进行大量的DOM操作,尽量使用AngularJS的脏检查机制。 - 尽量保持指令单一职责,使其易于理解和维护。 - 使用`ngAnimate`与其他指令结合,增强用户体验。 总结来说,AngularJS自定义指令是构建...

    AngularJS-Validation-Library:AngularJS 的一些验证指令

    AngularJS的内置验证机制主要体现在表单控件(如`ng-model`)上,通过`ng-form`或`form`指令创建表单,然后在输入元素上使用`ng-model`来绑定数据,并利用诸如`required`、`minlength`、`maxlength`、`pattern`等...

    AngularJS-Services-InDepth:AngularJS-服务-深度BookLogger

    在AngularJS中,服务是可重用的、单一职责的代码块,它们可以跨控制器、指令等不同组件共享数据和功能。本资料将深入探讨AngularJS服务的概念、类型、创建及应用,帮助开发者更好地理解和利用这一强大工具。 ### 1....

    AngularJS 自定义指令 - ECharts 2 雷达图

    另外,可以使用`$timeout`或`$apply`确保AngularJS的脏检查机制能正确更新视图。 8. **示例代码**: ``` angular.module('myApp').directive('echartsRadar', function() { return { restrict: 'E', scope: { ...

    angularjs-autocomplete-project

    2. **数据绑定**:研究如何使用AngularJS的数据绑定机制将视图与模型同步。 3. **指令的创建和使用**:深入理解AngularJS指令的工作原理,如何创建自定义指令并将其集成到应用中。 4. **服务的使用**:了解如何...

    angular-sly-directive:狡猾的角度指令

    而"angular-sly-directive"是针对AngularJS的一个自定义指令,它引入了Sly.js库,以实现更高级的滚动和滑动效果。 Sly.js是一个轻量级的JavaScript库,专门用于处理单页应用(SPA)中的滚动和轮播效果。它特别适合...

    angular-form-wizard-directive:用于字段集到 Bootstrap 表单向导转换器的 AngularJS 指令

    在这个场景中,我们关注的是一个名为“angular-form-wizard-directive”的工具,这是一个专为AngularJS设计的自定义指令,用于将一组`&lt;fieldset&gt;`元素转换成具有引导功能的Bootstrap表单向导。这个指令能够帮助...

    前端项目-angular-mapboxgl-directive.zip

    AngularJS的指令是用于扩展HTML功能的核心机制,将Mapbox GL封装为一个指令意味着开发者可以通过AngularJS的方式来控制和操作地图。 **标签解析:** "前端项目" 这个标签明确了这个压缩包的内容主要涉及前端开发,...

    angular-parse-auth-directive:强制用户登录(使用 Parse.com)以查看其内容的 Angular 指令

    标题 "angular-parse-auth-directive" 提供了一个关于 AngularJS(Angular 1.x 版本)应用中的特定功能的线索,即一个自定义指令,用于强制用户通过 Parse.com 进行身份验证才能访问受保护的内容。Parse.com 是一个...

    form-validation-angularjs-example:如何使用 AngularJS 进行表单验证

    AngularJS,作为一个强大的JavaScript框架,提供了内置的机制来处理客户端的表单验证,从而为用户提供了实时、交互式的反馈,增强了用户体验。 ### 一、AngularJS 表单基础 AngularJS中的表单是通过`&lt;form&gt;`元素...

    Timer-Custom-Directive:以 hh ss 格式显示时间的自定义指令

    在AngularJS中,指令是用于增强HTML的一种机制,它们可以监听DOM事件、修改DOM结构,甚至像本例中那样,动态更新内容。自定义指令通过`ngDirective`模块定义,通常包含`link`、`controller`、`template`、`restrict`...

    ANGULARJS中用NG-BIND指令实现单向绑定的例子

    AngularJS最大的特点就是它的双向数据绑定以及依赖注入机制,这使得开发动态web应用变得更加容易和快捷。它将应用的结构、视图和模型分离开来,利用数据绑定和依赖注入等核心功能来简化应用开发。 在AngularJS中,...

    angularjs指令 下拉框

    在AngularJS中,指令是用于扩展HTML的一种机制,它们让开发者可以定义自定义的DOM行为。"angularjs指令 下拉框"这个主题聚焦于如何利用AngularJS创建一个自定义的下拉框(Dropdown)指令。下拉框在Web开发中非常常见...

    angular-line-links-directive

    标题“angular-line-links-directive”指的是一个AngularJS的自定义指令,它的主要功能是创建连接对象的线,这些对象可以在界面上被拖动。这个工具可能是为了帮助开发者在UI设计中构建更动态、交互性更强的图形元素...

    详解angularJs中自定义directive的数据交互

    总结起来,AngularJS自定义指令的数据交互涉及作用域的隔离、数据绑定、函数调用以及事件机制。通过灵活运用这些机制,可以构建出复杂的、高度可复用的组件,并确保数据在组件和应用程序之间正确流动。理解并掌握...

    Learning AngularJS.pdf (0分下载网)

    - **双向数据绑定**:AngularJS通过双向数据绑定机制将视图与控制器中的数据进行同步。 - **指令**:视图中可以使用AngularJS提供的指令来扩展HTML的功能,如`ng-repeat`、`ng-if`等。 #### 指令(Directive) - **...

Global site tag (gtag.js) - Google Analytics