关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » UI前端 »AngularJS 自定义 Directive 及代码示例

    AngularJS 自定义 Directive 及代码示例

    2015-05-20 00:00:00 出处:ITJS
    分享

    前面一篇介绍了各种常用的AngularJS内建的Directives以及对应的代码实例。这篇我们再看看如何创建自己的Directive吧!

    什么时候需要自定义Directive?

    1. 使你的Html更具语义化,不需要深入研究代码和逻辑即可知道页面的大致逻辑。

    2. 抽象一个自定义组件,在其他地方进行重用。

    看一下如下2个代码片段:

    示例1:

    <body>
        <div>
            <p>This is your class name.</p>
            <div>
                <p>Your teacher:</p>
                <p>Mr. Wang</p>
                <p>35 years old</p>
                <p>English</p>
                <p>Descriptions: 1.85cm tall, with a pair of brown glasses, unmarried, easy going etc.</p>
            </div>
            <div>
                <div>
                    <p>Students in the class:</p>
                    <div>
                        <p>Jack</p>
                        <p>Male</p>
                        <p>15</p>
                        <p>Description: Smart ...</p>
                    </div>
                    <div>
                        <p>May</p>
                        <p>Female</p>
                        <p>14</p>
                        <p>Description: Diligent ...</p>
                    </div>
                    <div>
                        <p>Tom</p>
                        <p>Male</p>
                        <p>15</p>
                        <p>Description: Naughty ...</p>
                    </div>
                    <div>
                        <p>Alice</p>
                        <p>Female</p>
                        <p>14</p>
                        <p>Description: Smart ...</p>
                    </div>
                </div>
            </div>
        </div>
    </body>

    示例2:

    1 <body ng-app>
    2     <class-info>
    3         <teacher-info></teacher-info>
    4         <student-infos></student-infos>
    5     </class-info>
    6 </body>

    示例1中的代码你可能要完整的看完才能知道逻辑(当然示例1也不复杂,你可以想象下真实的场景要比这个复杂的多的多),不是说示例2中的代码少(逻辑被转移到其他地方去了),而是在示例2中,光看Html标签就知道这个页面是在展示班级信息,班级信息中还有班主任的信息和所有学生的信息。

    另外,示例1中,若一个班级的学生有30个,学生信息的Html会出现30次,假如将来发生变动,这30出学生信息的代码都需要改动。

    制作一个属于自己的Directive

    示例3:

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('ngCustomDirectiveTest', []);
                app.controller('myController', ['$scope', function ($scope) {
                    $scope.info = {
                        yourname: 'Jack',
                        template: 'template.html'
                    };
                }]);
    
                // 自定义Element的Directive
                app.directive("studentInfo", function () {
                    return {
                        // A 代表 Attribute
                        // C 代表 Class
                        // E 代表 Element
                        // ACE 表示同时创建 A、C、E 三种
                        restrict: 'ACE',
                        // templateUrl 指向独立的Html文件,AngularJS会用Html文件中的内容替换studentInfo对象
                        templateUrl: 'template.html'
                    };
                });
            })();
        </script>
    </head>
    <body ng-app="ngCustomDirectiveTest">
        <div ng-controller="myController as myCtrl">
            <student-info></student-info>
            <br />
            <data-student-info></data-student-info>
            <br />
    
            <div student-info></div>
            <br />
            <div data_student-info></div>
            <br />
    
            <div class="student-info"></div>
            <br />
            <div class="data-student-info"></div>
            <br />
        </div>
    </body>
    </html>

    template.html:

    1 <div>
    2     <p>This is a custom template.</p>
    3     <p>Your name: {{info.yourname}}</p>
    4 </div>

    注意:你可能还见过restrict:’M',或者Directive的命名以pre_suf、pre:suf这样的代码书写方式,这些都已经“过时”了,最潮的restrict仅使用ACE三种,命名方式使用pre-suf。

    另外,你可能疑惑,为什么加上”data-”前缀的为什么也能被解析?实际上AngularJS在处理Directive时,首先会忽略Directive命名中的”data-”或者”x-”前缀,因此无论你加上”data-”还是”x-”,AngularJS还是能正确解析的,不过”x-”也是一种过时的写法,我们可以忽略。

    好了,是不是很容易?属于我们自己的Directive就这样创建成功了,接着让我们更深入一些,看一下Directive的scope属性。首先看一下以下3段代码:

    示例4(student-info直接使用了包含它的Controller的Scope中的变量jack和alice):

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('ngCustomDirectiveTest', []);
                app.controller('myController', ['$scope', function ($scope) {
                    $scope.jack = {
                        name: 'Jack',
                        sex: 'Male'
                    },
                    $scope.alice = {
                        name: 'Alice',
                        sex: 'Female'
                    }
                }]);
    
                app.directive("studentInfo", function () {
                    return {
                        restrict: 'E',
                        template: '<div><p>Student name: {{jack.name}}</p><p>Student sex: {{jack.sex}}</p></div><br /><div><p>Student name: {{alice.name}}</p><p>Student sex: {{alice.sex}}</p></div>'
                    };
                });
            })();
        </script>
    </head>
    <body ng-app="ngCustomDirectiveTest">
        <div ng-controller="myController as myCtrl">
            <student-info></student-info>
        </div>
    </body>
    </html>

    示例5(和示例1类似,直接使用包含student-info的Controller中的变量students,在template中使用ng-repeat展示学生信息):

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('ngCustomDirectiveTest', []);
                app.controller('myController', ['$scope', function ($scope) {
                    $scope.students = [
                        {
                            name: 'Jack',
                            sex: 'Male'
                        },
                        {
                            name: 'Alice',
                            sex: 'Female'
                        }
                    ];
                }]);
    
                app.directive("studentInfo", function () {
                    return {
                        restrict: 'E',
                        template: '<div ng-repeat="stu in students"><p>Student name:{{stu.name}}</p><p>Student sex:{{stu.sex}}</p></div>'
                    };
                });
            })();
        </script>
    </head>
    <body ng-app="ngCustomDirectiveTest">
        <div ng-controller="myController as myCtrl">
            <student-info></student-info>
        </div>
    </body>
    </html>

    示例6(定义两个不同的Controller:jackController和aliceController,使student-info处于2个不同的controller中):

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('ngCustomDirectiveTest', []);
                app.controller('jackController', ['$scope', function ($scope) {
                    $scope.student =
                        {
                            name: 'Jack',
                            sex: 'Male'
                        }
                }]);
    
                app.controller('aliceController', ['$scope', function ($scope) {
                    $scope.student =
                        {
                            name: 'Alice',
                            sex: 'Female'
                        }
                }]);
    
                app.directive("studentInfo", function () {
                    return {
                        restrict: 'E',
                        template: '<div><p>Student name:{{student.name}}</p><p>Student sex:{{student.sex}}</p></div>'
                    };
                });
            })();
        </script>
    </head>
    <body ng-app="ngCustomDirectiveTest">
        <div ng-controller="jackController as jackCtrl">
            <student-info></student-info>
        </div>
        <br />
        <div ng-controller="aliceController as aliceCtrl">
            <student-info></student-info>
        </div>
    </body>
    </html>

    上述三种方式,都能达到我们所需的目的:自定义一个名为student-info的Directive,展示Controller中的学生信息。但仔细分析上述3种不同的代码,能发现它们各自有不同的问题:

    1. 示例4中,student-info的template中的所有表达式严重依赖Controller中的变量定义,导致student-info无法抽象成一个公共的学生信息展示模块。

    2. 示例5中,虽然使用ng-repeat封装了代码,但是还是存在依赖Controller中students变量的问题,示例5仅比示例4稍微好点。

    3. 示例6中,定义了不同的Controller来隔离作用域,但N个学生需要定义N个作用域,并且定义Controller时,还是必须定义一个名为student的变量,否则代码无法正确执行,因此还是存在耦合性。

    好吧,让我们看看AngularJS为我们提供的优雅的解决方案-Isolate scope:

    示例7(通过使用=attr将Isolate scope中的属性赋值给Directive的名为’attr’的Attribute):

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('ngCustomDirectiveTest', []);
                app.controller('myController', ['$scope', function ($scope) {
                    $scope.jack = {
                        name: 'Jack',
                        sex: 'Male'
                    },
                    $scope.alice = {
                        name: 'Alice',
                        sex: 'Female'
                    }
                }]);
    
                app.directive("studentInfo", function () {
                    return {
                        restrict: 'E',
                        // 定义student-info的Isolate scope
                        scope: {
                            // 作用域内定义一个变量:newNameInScope
                            // 值对应到Directive中的info属性
                            newNameInScope: '=info'
                        },
                        // template 不再依赖外部, 仅依赖内部的newNameInScope变量
                        template: '<div><p>Student name: {{newNameInScope.name}}</p><p>Student sex: {{newNameInScope.sex}}</p></div>'
                    };
                });
            })();
        </script>
    </head>
    <body ng-app="ngCustomDirectiveTest">
        <div ng-controller="myController as myCtrl">
            <!--将myController中的jack属性传递给info-->
            <student-info info="jack"></student-info>
            <br />
            <!--将myController中的alice属性传递给info-->
            <student-info info="alice"></student-info>
        </div>
    </body>
    </html>

    不同之处已经在注释中说明,示例7已经完全将student-info与外界隔离,不在存在耦合性,真正达到了我们自定义Directive的目的2(见本文”什么时候需要自定义Directive”部分)。

    让我们再对示例7进行一些调整:

    示例8:

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('ngCustomDirectiveTest', []);
                app.controller('myController', ['$scope', function ($scope) {
                    $scope.jack = {
                        name: 'Jack',
                        sex: 'Male'
                    },
                    $scope.alice = {
                        name: 'Alice',
                        sex: 'Female'
                    }
                }]);
    
                app.directive("studentInfo", function () {
                    return {
                        restrict: 'E',
                        scope: {
                            newNameInScope: '=info'
                        },
                        // 这里的alice将不能获取Controller中的变量alice的信息
                        template: '<div><p>Student name: {{newNameInScope.name}}</p><p>Student sex: {{newNameInScope.sex}}</p><br /><p>Deskmate name: {{alice.name}}</p><p>Deskmate sex: {{alice.sex}}</p></div>'
                    };
                });
            })();
        </script>
    </head>
    <body ng-app="ngCustomDirectiveTest">
        <div ng-controller="myController as myCtrl">
            <student-info info="jack"></student-info>
        </div>
    </body>
    </html>

    这个就是所谓的封闭(Isolate),对比一下示例4,当创建student-info时指定了scope属性后,不在scope中指定的变量,在student-info中将无法被识别,做到了“封闭”。这样,当你定义一个公共模块时,不会因为在不同的Controller中使用而产生意想不到的问题。因此当你需要定义一个具有隔离性的Directive时,即使不需要传递Controller中的变量,也务必加上scope属性。

    不过我们只能将一个字符串或者一个对象传入Isolate scope中,试想若遇到某些特殊情况,需要直接包含指定的Html片段时怎么办?AngularJS也是有这样的功能的。

    示例9:

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('ngCustomDirectiveTest', []);
                app.controller('myController', ['$scope', function ($scope) {
                    $scope.jack = {
                        name: 'Jack',
                        sex: 'Male'
                    },
                    $scope.alice = {
                        name: 'Alice',
                        sex: 'Female'
                    }
                }]);
    
                app.directive("studentInfo", function () {
                    return {
                        restrict: 'E',
                        // 指定transclude属性为true
                        transclude: true
                    };
                });
            })();
        </script>
    </head>
    <body ng-app="ngCustomDirectiveTest">
        <div ng-controller="myController as myCtrl">
            <!--指明student-info将会使用transclude模式-->
            <student-info ng-transclude>
                <!-- student-info的内容由使用者自己指定,并且内容中能访问student-info的scope以外的变量 -->
                <p>Student name: {{jack.name}}</p>
                <p>Student sex: {{jack.sex}}</p>
                <br />
                <p>Deskmate name: {{alice.name}}</p>
                <p>Deskmate sex: {{alice.sex}}
            </student-info>
        </div>
    </body>
    </html>

    其他自定义Directive的示例

    示例10(自定义Directive操作DOM,官方文档中的demo):

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('docsTimeDirective', []);
    
                app.controller('Controller', ['$scope', function ($scope) {
                    $scope.format = 'M/d/yy h:mm:ss a';
                }])
    
                app.directive('myCurrentTime', ['$interval', 'dateFilter', function ($interval, dateFilter) {
                    function link(scope, element, attrs) {
                        var format,
                            timeoutId;
    
                        function updateTime() {
                            element.text(dateFilter(new Date(), format));
                        }
    
                        scope.$watch(attrs.myCurrentTime, function (value) {
                            format = value;
                            updateTime();
                        });
    
                        element.on('$destroy', function () {
                            $interval.cancel(timeoutId);
                        });
    
                        timeoutId = $interval(function () {
                            updateTime();
                        }, 1000);
                    }
    
                    return {
                        link: link
                    };
                }]);
            })();
        </script>
    </head>
    <body ng-app="docsTimeDirective">
        <div ng-controller="Controller">
            Date format:
            <input ng-model="format">
            <hr />
            Current time is: <span my-current-time="format"></span>
        </div>
    </body>
    </html>

    假如想要使Directive改变DOM,一般会用到link参数,其原型为:function link(scope, element, attrs) {…}:

    scope: 与当前元素结合的scope elment:当前元素 $attrs:当前元素的属性对象

    示例11(通过使用&attr开放Directive,将自定义的方法绑定到Directive上):

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('isoFnBindTest', []);
    
                app.controller('myController', ['$scope', function ($scope) {
                    $scope.name = '';
                    $scope.message = '';
                    $scope.isHide = true;
                    $scope.sayHello = function (message, name) {
                        $scope.isHide = false;
                        $scope.name = name;
                        $scope.message = message;
                        alert($scope.message + ',' + $scope.name);
                    };
                }]);
    
                app.directive('myGreeting', function () {
                    return {
                        restrict: 'E',
                        transclude: true,
                        scope: {
                            // Step 2: greet方法绑定到onGreet属性(对应Html中的on-greet),并将greet的输入参数传给onGreet
                            'greet': '&onGreet'
                        },
                        templateUrl: 'my-greeting.html'
                    };
                });
            })();
        </script>
    </head>
    <body ng-app="isoFnBindTest">
        <div ng-controller="myController">
            <!-- Step 3: on-greet指向了myController中的sayHello方法,此时on-greet中能直接访问到greet的输入参数-->
            <my-greeting on-greet="sayHello(message, name)">
                <div ng-hide="isHide">
                    {{message}}, {{name}}!
                </div>
            </my-greeting>
        </div>
    </body>
    </html>

    my-greeting.html:

    1 <div>
    2   <!-- Step1: 一旦触发click, 将调用Isolate scope中的greet方法-->
    3   <button ng-click="greet({message: 'Hello', name: 'Tom'})">Click me!</button>
    4   <div ng-transclude></div>
    5 </div>

    示例12(Directive侦听事件,官方Demo):

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('dragModule', []);
    
                app.directive('myDraggable', ['$document', function ($document) {
                    return {
                        link: function (scope, element, attr) {
                            var startX = 0, startY = 0, x = 0, y = 0;
    
                            element.css({
                                position: 'relative',
                                border: '1px solid red',
                                backgroundColor: 'lightgrey',
                                cursor: 'pointer'
                            });
    
                            element.on('mousedown', function (event) {
                                // Prevent default dragging of selected content
                                event.preventDefault();
                                startX = event.pageX - x;
                                startY = event.pageY - y;
                                $document.on('mousemove', mousemove);
                                $document.on('mouseup', mouseup);
                            });
    
                            function mousemove(event) {
                                y = event.pageY - startY;
                                x = event.pageX - startX;
                                element.css({
                                    top: y + 'px',
                                    left: x + 'px'
                                });
                            }
    
                            function mouseup() {
                                $document.off('mousemove', mousemove);
                                $document.off('mouseup', mouseup);
                            }
                        }
                    };
                }]);
            })();
        </script>
    </head>
    <body ng-app="dragModule">
        <span my-draggable>Drag ME</span>
    </body>
    </html>

    示例13(Directive之间的相互作用,官方Demo):

    <!DOCTYPE>
    <html>
    <head>
        <script src="/Scripts/angular.js"></script>
        <script type="text/javascript">
            (function () {
                var app = angular.module('docsTabsExample', []);
    
                app.directive('myTabs', function () {
                    return {
                        restrict: 'E',
                        transclude: true,
                        scope: {},
                        controller: function ($scope) {
                            var panes = $scope.panes = [];
    
                            $scope.select = function (pane) {
                                angular.forEach(panes, function (pane) {
                                    pane.selected = false;
                                });
                                pane.selected = true;
                            };
    
                            this.addPane = function (pane) {
                                if (panes.length === 0) {
                                    $scope.select(pane);
                                }
                                panes.push(pane);
                            };
                        },
                        templateUrl: 'my-tabs.html'
                    };
                });
    
                app.directive('myPane', function () {
                    return {
                        // 指定必须有myTabs对象,若对象不存在则会报错,见下面的图1
                        require: '^myTabs',  // ^ 表示将在父级的范围内查找该对象, 没有 ^ 表示在Directive内查找该对象, 若范围指定错误无法找到myTabs,js则会报错
                        restrict: 'E',
                        transclude: true,
                        scope: {
                            title: '@'
                        },
                        link: function (scope, element, attrs, tabsCtrl) {
                            tabsCtrl.addPane(scope);
                        },
                        templateUrl: 'my-pane.html'
                    };
                });
            })();
        </script>
    </head>
    <body ng-app="docsTabsExample">
        <my-tabs>
          <my-pane title="Hello">
            <h4>Hello</h4>
            <p>Lorem ipsum dolor sit amet</p>
          </my-pane>
          <my-pane title="World">
            <h4>World</h4>
            <em>Mauris elementum elementum enim at suscipit.</em>
            <p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p>
          </my-pane>
        </my-tabs>
    </body>
    </html>

    my-tabs.html:

     <div class="tabbable">
       <ul class="nav nav-tabs">
         <li ng-repeat="pane in panes" ng-class="{active:pane.selected}">
           <a href="" ng-click="select(pane)">{{pane.title}}</a>
         </li>
       </ul>
       <div class="tab-content" ng-transclude></div>
     </div>

    my-pane.html:

    <div class="tab-pane" ng-show="selected" ng-transclude>
    </div>

    参考资料

    AngularJS官方文档:https://docs.angularjs.org/guide/directive

    CodeSchool快速入门视频:http://campus.codeschool.com/courses/shaping-up-with-angular-js/intro

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    正版 Windows 11产品密钥怎么查找/查看?

    还有3个月,微软将停止 Windows 10 的更新

    Windows 10 终止支持后,企业为何要立即升级?

    Windows 10 将于 2025年10 月终止技术支持,建议迁移到 Windows 11

    Windows 12 发布推迟,微软正全力筹备Windows 11 25H2更新

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    IT头条

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    液冷服务器概念股走强,博汇、润泽等液冷概念股票大涨

    01:17

    亚太地区的 AI 驱动型医疗保健:2025 年及以后的下一步是什么?

    16:30

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    技术热点

    商业智能成CIO优先关注点 技术落地方显成效(1)

    用linux安装MySQL时产生问题破解

    JAVA中关于Map的九大问题

    windows 7旗舰版无法使用远程登录如何开启telnet服务

    Android View 事件分发机制详解

    MySQL用户变量的用法

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。