仅仅对AngularJS-指令所有参数的见解

指令-directive
          (第一篇博客,打个印记)

         angular这门框架遵循MVC来设计的,模块化开发,(它自己也是用模块化来组织自己的代码的),angular的C层(controller)是不建议直接操作DOM的,本来操作DOM成本就很高,加上angular内部实现的脏检查机制,所以说是非常不建议在控制器里面操作DOM,相比jQuery,angular算的上是一门真正的js框架,jQuery个人理解就是一个封装的简化版DOM API,当然了,谷歌爸爸也考虑的很周全,在angular内部封装了Jqite。

            所谓指令,就是AngularJs用来专门封装来操作DOM的功能,(题主刚开始学习angular的时候觉得最难理解的就是指令),也是angular几个核心概念之一。

           废话不多说,直接上代码。(没代码你谈个毛线)

           这里我直接用的ionic,别问为什么因为任性。

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Title</title>
    <script src="../lib/ionic.bundle.js"></script>
</head>
<body ng-controller="myCtrl">
<ion-header class="bar bar-header bar-light">{{title}}</ion-header>

            <modal-frame></modal-frame>

<script>
    var app=angular.module("myApp",['ionic']);
    app.controller("myCtrl",['$scope',function ($scope) {
        $scope.title="demo03";
    }]);
    app.directive("modalFrame",function () {
        return {
            restrict:"AE",
            template: '<div>HELLO directive</div>'
        }
    })
</script>
</body>
</html>

        一个简单的hello directive指令

指令的参数很多,借鉴别人博客。

angular.module('app', [])
.directive('myDirective', function() {
    return {
    restrict: String,                
    priority: Number,
    terminal: Boolean,
    template: String or Template Function:
    function(tElement, tAttrs) {...},
    templateUrl: String,
    replace: Boolean or String,
    scope: Boolean or Object,
    transclude: Boolean,
    controller: String or
    function(scope, element, attrs, transclude, otherInjectables) { ... },
    controllerAs: String,
    require: String,
    link: function(scope, iElement, iAttrs) { ... },
    compile: // 返回一个对象或连接函数,如下所示:
    function(tElement, tAttrs, transclude) {
        return {
            pre: function(scope, iElement, iAttrs, controller) { ... },
            post: function(scope, iElement, iAttrs, controller) { ... }
           }
        return function postLink(...) { ... }
        }
    };
 });

可能一下子说不了那么多,因为有些我自己也用得少。

scope:

scope参数是可选的,默认值为false,可选true、对象{};

  • false:共享父域

  • true:继承父域,且新建独立作用域

  • 对象{}:不继承父域,且新建独立作用域

false、true、{}三者对比

<body>
    <div ng-controller='parentCtrl'>
        <h3>指令scope参数——false、true、{}对比测试</h3>
        parent:
        <div>
            <span> {{parentName}}</span>
            <input type="text" ng-model="parentName" />
        </div>
        <br />
        <child-a></child-a>
        <br />
        <child-b></child-b>
        <br />
        <child-c parent-name="parentName"></child-c>
    </div>
    <!--t1指令模板-->
    <script type="text/html" id="t1">
        <div>
            <span>{{parentName}}</span>
            <input type="text" ng-model="parentName" />
        </div>
    </script>
    <script>
        var app = angular.module("app", []);

        app.controller('parentCtrl', function ($scope) {
            $scope.parentName = "parent";
        })

        //false:共享作用域
        app.directive('childA', function () {
            return {
                restrict: 'E',
                scope: false,
                template: function (elem, attr) {
                    return "false:" + document.getElementById('t1').innerHTML;
                }
            };
        });

        //true:继承父域,并建立独立作用域
        app.directive('childB', function () {
            return {
                restrict: 'E',
                scope: true,
                template: function (elem, attr) {
                    return "true:" + document.getElementById('t1').innerHTML;
                },
                controller: function ($scope) {
                    $scope.parentName = "parent";

                    //已声明的情况下,$scope.$watch监听的是自己的parentName
                    $scope.$watch('parentName', function (n, o) {
                        console.log("child watch" + n);
                    });

                    //$scope.$parent.$watch监听的是父域的parentName
                    $scope.$parent.$watch('parentName', function (n, o) {
                        console.log("parent watch" + n);
                    });
                }
            };
        });

        //{}:不继承父域,建立独立作用域
        app.directive('childC', function () {
            return {
                restrict: 'E',
                scope: {},
                template: function (elem, attr) {
                    return "{}:" + document.getElementById('t1').innerHTML;
                },
                controller: function ($scope) {
                    console.log($scope);
                }
            };
        });

    </script>
</body>
false参数
本质:子域与父域共享作用域。
特点:父域修改parentName的同时,指令绑定的parentName的元素会被刷新。
反之,指令内部parentName被修改时,父域的parentName同样会被刷新。

true参数
本质:子域继承父域,并建立独立作用域。
特点:
1、在指令已声明parentName的情况下,父域parentName变更,指令中parentName不会发生变化。
指令在true参数下,建立了的scope,独立并隔离与父控制器的scope。
        
controller: function ($scope) {
    $scope.parentName = "parent";
}

反之,指令中parentName变更,父域也不会发生变化

2、在指令未声明parentName的情况下,父域的parentName变更,指令中parentName也会刷新

这种情况很多时候会被忽略,指令的scope没有声明对象时,其元素绑定的仍然是父域的对象。但,一旦指令中Input变更了,对应的独立scope也会自动声明该绑定对象,这就回到了第1种情况。

controller: function ($scope) {
    //$scope.parentName = "parent";
}

然而,指令中parentName变更,父域是不会变化的;

3、在指令已声明parentName的情况下 ,在指令中监听父域parentName 的变化无效。但监听子域parentName的变化有效

独立子域scope,只能监听自己的,不能监听父域的。但通过 $scope.$parent可以监听父域。

controller: function ($scope) {
    $scope.parentName = "parent" ;

    //已声明的情况下,$scope.$watch监听的是自己的parentName
    $scope.$watch( 'parentName' , function (n, o) {
        console.log("child watch" + n);
    });

    //$scope.$parent.$watch监听的是父域的parentName
    $scope.$parent.$watch( 'parentName' , function (n, o) {
        console.log("parent watch" + n);
    });
}
4、在指令未声明parentName的情况下 ,在指令中监听父域parentName的变化有效。

这里就不解释了,参考第2点,大家可以动手试一下。

controller: function ($scope) {
    //$scope.parentName = "parent";

    //未声明的情况下,$scope.$watch监听的是父域的parentName
    $scope.$watch('parentName' , function (n, o) {
        console.log("child watch" + n);
    });
}
对象{}参数
本质:子域不继承父域,并建立独立作用域。
特点:
1、当scope对象为空对象时,无论是父域parentName,还是指令子域parentName发生变更,都不会影响到对方。

原理很清楚,就是指令建立的独立作用域,与父域是完全隔离的。

scope: {}

2、当scope对象为非空对象时,指令会将该对象处理成子域scope的扩展属性。而父域与子域之间传递数据的任务,就是可以通过这块扩展属性完成。

<div ng-controller='parentCtrl'>
    parent:
    <p><span>{{name}}</span><input type="text" ng-model="name" /></p>
    <p><span>{{sexy}}</span><input type="text" ng-model="sexy" /></p>
    <p><span>{{age}}</span><input type="text" ng-model="age" /></p>
    <br />

    <!--特别注意:@与=对应的attr,@是单向绑定父域的机制,记得加上{{}};&对应的attrName必须以on-开头-->
    <child-c my-name="name" my-sexy-attr="sexy" my-age="{{age}}" on-say="say('i m ' + name)"></child-c>
</div>

<!--t1指令模板-->
<script type="text/html" id="t1">
    <div>
        <span>{{myName}}</span>
        <input type="text" ng-model="myName" />
    </div>
    <div>
        <span>{{mySexy}}</span>
        <input type="text" ng-model="mySexy" />
    </div>
    <div>
        <span>{{myAge}}</span>
        <input type="text" ng-model="myAge" />
    </div>
</script>

<script>
    var app = angular.module("app", []);

    app.controller('parentCtrl', function ($scope) {
        $scope.name = "mark";
        $scope.sexy = "male";
        $scope.age = "30";
        $scope.say = function (sth) {
            alert(sth);
        };
    })

    app.directive('childC', function () {
        return {
            restrict: 'E',
            scope: {
                myName: '=',
                mySexy: '=mySexyAttr',
                myAge: '@',
                onSay: '&'
            },
            template: function (elem, attr) {
                return "{}:" + document.getElementById('t1').innerHTML;
            },
            controller: function ($scope) {
                console.log($scope.myName);
                console.log($scope.mySexy);
                console.log($scope.myAge);
                $scope.onSay();
            }
        };
    });

</script>

@(or @Attr)绑定策略——本地作用域属性,使用@符号将本地作用域同DOM属性的值进行绑定。指令内部作用域可以使用外部作用域的变量。(单向引用父域对象)

<child-c onSay="name"></child-c>
ps:=策略不需要加上{{}}进行绑定

scope: {          
     myName: '=',
}

& (or &Attr)绑定策略——通过&符号可以对父级作用域进行绑定,以便在其中运行函数。(调用父域函数)

<child-c on-say="say('i m ' + name)"></child-c>
ps:&对应的attrName必须以on-开头

scope: {          
     onSay: '&',
}

父域绑定调用函数及传参

app.controller('parentCtrl', function ($scope) {
     $scope.say = function (sth) {
         alert(sth);
     };
})
ps特别注意:@与=对应的attr,;
<child-c my-name="name" my-sexy-attr="sexy" my-age="{{age}}" on-say="say('i m ' + name)"></child-c>
总结下来,scope扩展对象,既能够解耦父域与子域共域的问题,也能够实现指令与外界通讯的问题,是Angular开发指令化模块化的重要基础。在往后的章节,我会向大家介绍指令化开发的更多实例。


阅读更多
文章标签: AngularJs 指令 mvc
个人分类: AngularJs
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭