`

《AngularJS》5个实例详解Directive(指令)机制

 
阅读更多

《AngularJS》5个实例详解Directive(指令)机制

angular1下载:https://code.angularjs.org/ 

大漠穷秋

 

本文整理并扩展了《AngularJS》这本书第六章里面的内容,此书近期即将由电子工业出版社出版,敬请期待口令:Angular

 

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官方站点在这里:http://angularjs.org/

 

[全文完]

 

其它相关内容:

1、OReilly的《AngularJS》已由电子工业出版社出版

http://damoqiongqiu.iteye.com/blog/1965167

2、对比Angular/jQueryUI/Extjs:没有一个框架是万能的

http://damoqiongqiu.iteye.com/blog/1922004

3、AngularJS表单基础

http://damoqiongqiu.iteye.com/blog/1920191

4、AngularJS Form 进阶:远程校验和自定义输入项

http://damoqiongqiu.iteye.com/blog/1920993

5、AngularJS:在Windows上安装Yeoman

http://damoqiongqiu.iteye.com/blog/1885371

6、使用JsTestDriver实现JavaScript单元测试

http://damoqiongqiu.iteye.com/blog/1924415

 

分享到:
评论

相关推荐

    Angularjs自定义指令Directive详解

    在本文中,我们将详细介绍AngularJS的自定义指令的创建和使用方法,以及如何通过实例代码来实现一个特定的功能。 AngularJS自定义指令的创建通常通过定义一个模块,并在该模块中使用`.directive()`方法注册一个指令...

    AngularJS自定义控件实例详解

    本文将详细介绍AngularJS自定义控件的创建方法,并通过实例来深入探讨如何使用自定义指令和模板操作的相关函数与技巧。 首先,需要了解AngularJS中什么是自定义控件。在AngularJS中,自定义控件通常是通过自定义...

    AngularJS 自定义指令详解及实例代码

    AngularJS是一个强大的前端JavaScript框架,其核心特性之一就是自定义指令。自定义指令允许开发者扩展HTML,创建新的元素或属性,以实现特定的功能。在本文中,我们将深入探讨AngularJS自定义指令的创建、使用以及...

    AngularJs中的Modules详解

    ### AngularJs中的Modules详解 #### 一、什么是Module? 在AngularJS中,**Module**扮演着极其重要的角色,它是组织应用程序的基本单位。许多应用程序都具备一个main方法来初始化和启动应用,而AngularJS则通过**...

    AngularJS 指令的交互详解及实例代码

    1. **AngularJS 指令的创建与基本结构**:文档提到了如何创建基本的AngularJS指令,这涉及到AngularJS模块的创建以及使用module.directive()方法定义指令。每个指令都有其自己的配置对象,其中包括了定义指令行为的...

    AngularJS 0003: 指令

    **AngularJS 指令详解** AngularJS 是一个强大的前端JavaScript框架,用于构建单页应用程序(SPA)。在AngularJS中,指令是自定义HTML标签或属性,用于扩展HTML的功能,让网页具有更强的表现力和交互性。它们是...

    Angularjs使用directive自定义指令实现attribute继承的方法详解

    本文实例讲述了Angularjs使用directive自定义指令实现attribute继承的方法。分享给大家供大家参考,具体如下: 一、Html代码: &lt;!DOCTYPE html&gt; &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt; &lt;head&gt...

    详解AngularJS1.x学习directive 中‘& ’‘=’ ‘@’符号的区别使用

    AngularJS是一个非常流行的前端JavaScript框架,特别是在其1.x版本中,它通过各种内置指令和控制器,为开发者提供了强大的工具来创建动态网页。在AngularJS中,自定义指令(directive)是扩展HTML功能的一种方式,...

    AngularJS封装jQuery Datepicker

    **AngularJS 封装 jQuery Datepicker 知识点详解** 在Web开发中,日期选择器是一个常见的组件,用于用户输入日期或选择日期范围。AngularJS 和 jQuery 的结合使用可以为开发者提供更强大的功能和更好的用户体验。这...

    最新AngularJS开发宝典视频教程 后盾网AngularJS培训视频教程 后盾网.txt

    ├最新AngularJS开发宝典—第058讲 指令directive的link属性详解.mp4 ├最新AngularJS开发宝典—第059讲 tab面板组件的指令实现.mp4 ├最新AngularJS开发宝典—第060讲 服务server应用分析与使用场景.mp4 ├最新...

    AngularJs directive详解及示例代码

    当找到匹配的指令时,它会创建一个指令实例并与相应的DOM元素关联。 - 第三阶段,编译后的DOM与控制器(Controller)结合,指令开始执行其功能,如数据绑定、事件监听等。 5. **内置指令** AngularJS 提供了一组...

    详解angular 中的自定义指令之详解API

    这在多个控制器使用同一指令时特别有用,因为每个指令实例都有自己的作用域。 此外,还可以使用`require`属性来强制指令依赖于另一个指令,`link`函数来处理DOM元素和指令之间的交互,以及`priority`和`...

    AngularJS 自定义指令详解及示例代码

    编译函数只在初始化时执行一次,而链接函数在每个指令实例化时都会执行。 ### 示例代码解析 示例中创建了一个名为"student"的元素指令,它的作用是创建自定义的HTML标签,如&lt;student name="Mahesh"&gt;&lt;/student&gt;。...

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

    在AngularJS中,自定义指令是扩展框架功能的关键机制,允许开发者创建可重用的UI组件和行为。本文将深入探讨如何创建和使用自定义指令,以及如何利用它实现分页功能。 首先,创建自定义指令是通过调用`angular....

    AngularJS自定义表单验证功能实例详解

    AngularJS提供了内置的验证机制,但有时候,开发人员需要根据特定需求自定义验证逻辑。本文将深入探讨如何在AngularJS中实现自定义表单验证功能。 首先,AngularJS提供了多种内置的验证指令,如`required`、`...

    AngularJs Managing Service Dependencies详解

    首先,我们需要明确AngularJS中的服务(Service)是一种特殊的构造,用于封装业务逻辑,以便在不同的控制器(Controller)和指令(Directive)之间共享。服务可以通过依赖注入来声明和使用,这意味着服务的实现细节...

    AngularJS Module方法详解

    AngularJS 不仅仅是一个JavaScript库,它提供了一整套解决方案,包括模板机制、数据绑定、模块、指令、依赖注入和路由等功能,旨在简化开发过程,使开发者能够更专注于业务逻辑,而不是DOM操作。 在AngularJS中,...

Global site tag (gtag.js) - Google Analytics