Angular.JS中指令的参数有哪些
Angular.JS中指令的参数有哪些?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
指令的参数
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(...) { ... } } }; });
把它们分成三类:
描述指令或DOM本身特性的内部参数
连接指令外界、与其他指令或控制器沟通的对外参数
描述指令本身行为的行为参数
内部参数
restrict:String,E(元素)<my-directive></my-directive> A(属性,默认值)<div my-directive="expression"></div> C(类名)<div class="my-directive:expression;"></div> M(注释)<--directive:my-directive expression-->
priority: Number,指令执行优先级
template: String,指令链接DOM模板,例如“<h2>{{head}}</h2>”
templateUrl:String,DOM模板路径
replace: Boolean,指令链接模板是否替换原有元素,
对外参数——scope
scope参数非常重要,本应该是放到最后说明的,但是scope却是理解其他参数的关键,所以务必先跟大家说清楚。
scope参数的作用是,隔离指令与所在控制器间的作用域、隔离指令与指令间的作用域。
scope参数是可选的,默认值为false,可选true、对象{};
false:共享父域
true:继承父域,且新建独立作用域
对象{}:不继承父域,且新建独立作用域
false、true、{}三者对比
来看个例子
<body> <div ng-controller='parentCtrl'> <h4>指令scope参数——false、true、{}对比测试</h4> 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参数
本质:子域继承父域,并建立独立作用域。
特点:
在指令已声明parentName的情况下,父域parentName变更,指令中parentName不会发生变化。
指令在true参数下,建立了的scope,独立并隔离与父控制器的scope。
controller: function ($scope) { $scope.parentName = "parent";}
反之,指令中parentName变更,父域也不会发生变化。
在指令未声明parentName的情况下,父域的parentName变更,指令中parentName也会刷新
这种情况很多时候会被忽略,指令的scope没有声明对象时,其元素绑定的仍然是父域的对象。但,一旦指令中Input变更了,对应的独立scope也会自动声明该绑定对象,这就回到了第1种情况。
controller: function ($scope) { //$scope.parentName = "parent";}
然而,指令中parentName变更,父域是不会变化的;
在指令已声明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); });}
在指令未声明parentName的情况下 ,在指令中监听父域parentName的变化有效。
这里就不解释了,参考第2点,大家可以动手试一下。
controller: function ($scope) { //$scope.parentName = "parent"; //未声明的情况下,$scope.$watch监听的是父域的parentName $scope.$watch('parentName' , function (n, o) { console.log("child watch" + n); });}
对象{}参数
本质:子域不继承父域,并建立独立作用域。
特点:
当scope对象为空对象时,无论是父域parentName,还是指令子域parentName发生变更,都不会影响到对方。
原理很清楚,就是指令建立的独立作用域,与父域是完全隔离的。
scope: {}
当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 my-age="{{age}}"></child-c>
ps:@ 是单向绑定本地作用域,记得加上{{}}
scope: { myAge: '@',}
= (or =Attr)绑定策略——双向绑定:通过=可以将本地作用域上的属性同父级作用域上的属性进行双向的数据绑定。就像普通的数据绑定一样,本地属性会反映出父数据模型中所发生的改变。(双向引用父域对象)
<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开发指令化模块化的重要基础。在往后的章节,我会向大家介绍指令化开发的更多实例。
对外参数——require
scope是指令与外界作用域通讯的桥梁,而require是指令与指令之间通讯的桥梁。这个参数最大的作用在于,当要开发单指令无法完成,需要一些组合型指令的控件或功能,例如日期控件,通过require参数,指令可以获得外部其他指令的控制器,从而达到交换数据、事件分发的目的。
使用方法:require: String or Array
——String值为引入指令名称,并且有两个寻找指令策略符号‘?'与‘^';Array数组则为多个外部指令名称。
在link函数第4个参数ctrl中获取注入外部指令的控制器,如果require为String,ctrl为对象,如果require是数组,ctrl为数组。
require: '^teacher1',link: function ($scope, $element, $attrs, ctrl) { //ctrl指向teacher1指令的控制器}
?策略——寻找指令名称,如果没有找到,link函数第4个参数为null;如果没有?,则报错。
^ 策略——在自身指令寻找指令名称的同时,向上父元素寻找;如果没有^,则仅在自身寻找。
如下例子,指令studentA向上可以找到指令teacher及自身,但是不能找到相邻兄弟的student-b。
<div teacher> <student-a></student-a> <student-b></student-b></div>
完整例子
<body> <div teacher> {{name}} <student-a></student-a> <student-b></student-b> </div> <script> var app = angular.module("app", []); //studentA——require指向父级指令teacher app.directive('studentA', function () { return { require: '?^teacher', scope: {}, template: '<div>A`s teacher name: <span>{{teacherName}}</span></div>', link: function ($scope, $element, $attrs, ctrl) { //获取teacher指令控制器,并调用其方法sayName() $scope.teacherName = ctrl.sayName(); } }; }); //studentB——require指向父级指令teacher,及指令studentA //但是,由于不能获得兄弟,也没有采取?策略,导致报错 app.directive('studentB', function () { return { require: ['?^teacher', 'studentA'], scope: {}, template: '<div>B`s teacher name: <span>{{teacherName}}</span></div>', link: function ($scope, $element, $attrs, ctrl) { $scope.teacherName = ctrl.sayName(); } }; }); app.directive('teacher', function () { return { restrict: 'A', controller: function ($scope) { $scope.name = "Miss wang"; //扩展控制器的方法sayName,目的是让外部内获取控制器内部数据 this.sayName = function () { return $scope.name; }; } }; }); </script></body>
既然require可以获取外部指令,那Angular原生指令应该也是能够获取。其中最广泛应用的就是require: 'ngModel'
,关于ngModel在自定义指令上的应用,留待下回实例中再跟大家深入讨论。
行为参数——link与controller
为什么要把link与controller两个参数放到一起?
因为很多童鞋会把它们错误地混淆使用,包括我自己。
link与controller都是描述指令行为的参数,但它们是要描述的行为是完全不同的类型。
controller语法 controller:String or Function
controller本身的意义就是赋予指令控制器,而控制器就是定义其内部作用域的行为的。
所以controller要描述的是:指令的作用域的行为。
//指向匿名控制器controller: function ($scope) {},//指向控制器mainCtrlcontroller: "mainCtrl"
link语法 link:String Or Function
link名称是链接函数,啥意思,好像挺难理解。所以在解释链接函数之前,先要说一下Angular的初始化对于指令究竟做了什么。
Angular在刚从HTTP Response接收静态素材之初,会首先去分析母页HTML中有哪些原生指令或自定义指令,然后再去加载指令的template模板HTML,而template模板中又去加载自己的指令模板,如此类推,直到Angular找到了所有的指令及模板,形成模板树,并返回模板函数,提供给下一阶段进行数据绑定。
<body> <stu1 ></ stu1> <script > var app = angular.module("app" , []); app.directive( 'stu1' , function () { return { restrict: 'E' , template: "<p>1</p><stu2></stu2>" , link: function (scope) { console.log( 'stu1 running' ); } }; }); app.directive( 'stu2' , function () { return { restrict: 'E' , template: "<p>2</p><stu3></stu3>" , link: function (scope) { console.log( 'stu2 running' ); } }; }); app.directive( 'stu3' , function () { return { restrict: 'E' , template: "<p>3</p>" , link: function (scope) { console.log( 'stu3 running' ); } }; }); </script ></ body> console outputstu3 runningstu2 runningstu1 running
注意以上例子,在第一个断点stu3 running的时候,1 2 3 三个模板都渲染完成了。然后从最根部的stu3的link函数开始,依次执行stu 3 stu2 stu1的link函数。
简单来说就是:
加载模板,形成DOM模板树
@@@@
数据绑定
@@@@是啥?没错,就是link链接函数,它会在形成模板树之后,在数据绑定之前,从最底部指令开始,逐个指令执行它们的link函数。
在这个时间节点的link函数,操作DOM的性能开销是最低,非常适合在这个时机执行DOM的操作,例如鼠标操作或触控事件分发绑定、样式Class设置、增删改元素等等。
所以link就是描述指令元素操作行为。
link: function (scope, element, attr, ctrl) { element.bind("click", function () { console.log("绑定点击事件"); }); element.append("<p>增加段落块</p>"); //设置样式 element.css("background-color", "yellow"); //不推荐,在link中赋予scope行为 scope.hello = function () { console.log("hello"); };}
同理,在link中定义$scope行为是不推荐的。
这样想想,对于controller与link,就明白了。但还有一个问题,它们俩的执行顺序是?答案是先controller,后link。
放到全局顺序就是:
执行controller,设置各个作用域scope
加载模板,形成DOM模板树
执行link,设置DOM各个行为
数据绑定,最后scope绑上DOM
例子
<div student> {{name }} </div> <script> var app = angular.module("app", []); app.directive('student', function () { return { restrict: 'A', controller: function ($scope) { $scope.name = "tgor"; console.log('controller running'); }, link: function (scope, el) { el.append("<p>hello</p>"); console.log('link running'); } }; }); </script>
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注编程网行业资讯频道,感谢您对编程网的支持。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341