AngularJS 之 Directive 指令详解

实现语义化标签

<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>实现语义化标签</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js">
</script>
</head>
<body>
    <div ng-controller="MyController">
        <hello></hello>
    </div>
    <script>
        var appModule = angular.module('app',);
        appModule.directive('hello',function(){
            return{
                restrict:'E',
                template:'<div>Hi there</div>',
                replace:true
            };
        });
        appModule.controller('MyController',
            function ($scope,$timeout){
            }
        );
    </script>
</body>
</html>
  

指令声明方式选项 (restrict):

  • E:元素。例:<my-menu title=Products></my-menu>
  • A:属性。例:<div my-menu=Products></div>
  • C:元素。例:<div class=my-menu:Products></div>
  • M:元素。例:<!-- directive:my-menu Products -->

如果我们需要替换的 HTML 标签很长,显然不能用 拼接字符串的方式来写,这时候我们可以用templateUrl来替代template,从而可以把模板写到一个独立的 HTML 文件中。

transclude(变换)

<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>变换</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js">
</script>
</head>
<body>
    <div ng-controller="MyController">
        <hello>
            <br/>
            <span>原始的内容</span>
            <br/>
            <span>还会在这里</span>
            <br/>
            <p>新内容</p>
        </hello>
        <hello>
        </hello>
    </div>
    <script>
        var appModule = angular.module('app',);
        appModule.directive('hello',function(){
            return{
                restrict:'E',
                template:'<div>Hi there<span ng-transclude></span></div>',
                transclude:true
            };
        });
        appModule.controller('MyController',
            function ($scope,$timeout){
            }
        );
    </script>
</body>
</html>
  

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

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

<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>编译和连接</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js">
</script>
</head>
<body>
    <div ng-controller="MyController">
        <div ng-repeat='thing in things'>
            {{thing}}.<hello></hello>
        </div>
    </div>
    <script>
        var appModule = angular.module('app',);
        appModule.directive('hello',function(){
            return{
                restrict:'E',
                template:'<div>Hi there</div>',
                replace:true
            };
        });
        appModule.controller('MyController',
            function ($scope){
                $scope.things = [1,2,3,4,5,6];
            }
        );
    </script>
</body>
</html>
  

directive指令的本质其实是一个替换过程。 这个过程分为两个阶段,分别为compilelink

更好的一个例子

<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>编译和连接2</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js">
</script>
<style>
    .expander{
        border:1px solid black;
        width:250px;
    }

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

    .expander>.body{
        padding: .1em .3em;
    }
</style>
</head>
<body>
    <div ng-controller="MyController">
        <expander class='expander' expander-title='title'>
            {{text}}
        </expander>
    </div>
    <script>
        var appModule = angular.module('app',);
        appModule.directive('expander',function(){
            return{
                restrict:'EA',
                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;
                    }
                },
                replace:true,
                transclude:true
            };
        });
        appModule.controller('MyController',
            function ($scope){
                $scope.title = '点击展开';
                $scope.text = '这里是内部的内容。';
            }
        );
    </script>
</body>
</html>
  

综合实例

<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>directive指令综合</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js">
</script>
</head>
<body ng-controller="MyController">
    <div>
            <accordion>
                <expander class="expander" ng-repeat='expander in expanders' expander-title='expander.title'>
                    {{expander.text}}
                </expander>
            </accordion>
    </div>
    <script>
        var appModule = angular.module('app',);
        appModule.directive('accordion',function(){
            return{
                restrict:'EA',
                template:'<div ng-transclude></div>',
                replace:true,
                transclude:true,
                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);
                    }
                }
            }
        });

        appModule.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);
                    }
                }
            }
        });

        appModule.controller('MyController',
            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'
                    }
                ];
            }
        );
    </script>
</body>
</html>
  

部分转载自:http://damoqiongqiu.iteye.com/blog/1917971