关闭 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

    上一篇返回首页 下一篇

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

    别人在看

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

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

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

    帝国CMS7.5编辑器上传图片取消宽高的三种方法

    帝国cms如何自动生成缩略图的实现方法

    Windows 12即将到来,将彻底改变人机交互

    帝国CMS 7.5忘记登陆账号密码怎么办?可以phpmyadmin中重置管理员密码

    帝国CMS 7.5 后台编辑器换行,修改回车键br换行为p标签

    Windows 11 版本与 Windows 10比较,新功能一览

    Windows 11激活产品密钥收集及专业版激活方法

    IT头条

    无线路由大厂 TP-Link突然大裁员:补偿N+3

    02:39

    Meta 千万美金招募AI高级人才

    00:22

    更容易爆炸?罗马仕充电宝被北京多所高校禁用,公司紧急回应

    17:19

    天衍”量子计算云平台,“超算+量算” 告别“算力孤岛时代”

    18:18

    华为Pura80系列新机预热,余承东力赞其复杂光线下的视频拍摄实力

    01:28

    技术热点

    MySQL基本调度策略浅析

    MySQL使用INSERT插入多条记录

    SQL Server高可用的常见问题

    3D立体图片展示幻灯片JS特效

    windows 7上网看视频出现绿屏的原因及解决方法

    windows 7 64位系统的HOSTS文件在哪里?想用它加快域名解析

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

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