AngularJS使用directive自定義指令


AngularJS使用directive自定義指令

directive

除了AngularJS的內置指令,我們也可以通過.directive來創建自定義的指令。


app.directive("myDir",function(){
      return {
          template:"<h1>這是自定義指令</h1>"
      }
  })

命名

AngularJS要求自定義的Directive命名使用駝峰式語法。也就是從第二個單詞開始,每個單詞首字母大寫,並且不用任何連接符號。

命名 使用
dir dir
myDir my-dir
myDirArray my-dir-array

參數


restrict:String,                
priority:Number,
terminal:Boolean,
template:String or Template Function,
templateUrl:String or Template Function,
replace:Boolean or String,
transclude:Boolean,
scope:Boolean or Object,
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(...) { ... }
	}



這里是Directive的所有參數,下面我們主要介紹一下常用的參數restrict,template,scope,link,compile

組合使用例子

my-Directive

restrict

restrict描述了我們怎么使用自定義指令,以上面自定義的myDir為例

參數 使用
E(Element) <my-dir></my-dir>
A(attribute) <div my-dir></div>
C(class) <div class="my-dir"></div>
  • EAC可以組合使用

<body ng-controller="myCtrl">
	<my-dir></my-dir>
	<div my-dir></div>
    <script>
    angular.module('myApp', [])
	.controller("myCtrl", function($scope) {})
	.directive("myDir", function() {  
		return {  
			template: "<h1>這是自定義指令</h1>",
			restrict: "EA"  
		}  
	});
    </script>
</body>

scope

scope:為directive指定相關聯的作用域

參數 使用
false(默認值) 將使用parentscope;改變scope中的值,directive的值也會發生變化,反之亦如此
true 創建一個繼承parent``scope的子scope ;改變parent``scope中的值,子scope會發生變化;改變子scope中的值,parent``scope不會發生變化
{} 創建一個獨立的scope,可以使用 @ = &parent``scope進行屬性綁定;不繼承parent``scope改變任何一方都不影響對方
false和true

<!DOCTYPE html>
<html ng-app ="myApp">
<head>
<meta charset="utf-8">
<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
<style>
	
body{
  border: 5px solid #FF851B;
  padding: 10px;
}
.info{
  color:#0074D9;
}
.age{
  color:#FF4136;
}

</style>
</head>
<body ng-controller="myCtrl">
    <div><my-dire></my-dire></div>
	<div class="my-dirc"></div>
	<button ng-click="changeMyinfo()">changeInfo</button>
    <script>
    angular.module('myApp', [])
	.controller("myCtrl", function($scope) {
		 $scope.myage = 16;
 
		 $scope.myInfo = {
		        name:"chenjy"
		 };
		 
		 $scope.changeMyinfo = function(){
		        $scope.myage++;
		        $scope.myInfo.name += "_";
		 }
	})
	.directive("myDire", function() {
    return {
       template:"<h3>directive E</h3><div>my name:<span class='info'>{{myInfo.name}}</span>,my age:<span class='age'>{{myage}}</span></div>",
       restrict:"E",
       scope:false
    };
	}).directive("myDirc", function() {
	    return {
	       template:"<h3>directive C</h3><div>my name:<span class='info'>{{myInfo.name}}</span>,my age:<span class='age'>{{myage}}</span></div><div><input type='text' ng-model='myInfo.name'/><input type='text' ng-model='myage'/></div>",
	       restrict:"C",
	       scope:true
	    };
	})
    </script>
</body>
</html>

  • 我們點擊button會發現directive E``directive C的值都會發生變化,

  • 修改age對應的input框只有directive C的age會發生變化

@ = &

What is the difference between '@' and '=' in directive scope in AngularJS?

scope{}時,用三者的主要區別為

type describe
@ (@attr) Text binding / one-way binding
= (=attr) Direct model binding / two-way binding
& Behaviour binding / Method binding
  • @傳遞的是字符串不是對象

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
<style>
	
.app{
  border: 5px solid #FF851B;
  padding: 10px;
}
.info{
  color:#0074D9;
  
}

.age{
  color:#FF4136;
}
</style>
</head>
<body ng-controller="myCtrl">
    <div ng-app="App" ng-controller="Ctrl" class="app">
    <div ng-repeat = "info in infoList">
       <my-dir name="info.name" age="{{info.age}}" change-age="changeAge(info)"></my-dir>
    </div>
    </div>
    <script>
    angular.module("App", []).controller("Ctrl", ["$scope","$log","$sce",function($scope,$log, $sce) {
   
   $scope.infoList = [{
          name:"chenjy",
          age:16
   },{
          name:"tom",
          age:17
   },{
          name:"jerry",
          age:18
   }];
   
   $scope.changeAge = function(info){
          info.age++;
   }
   
   $scope.showLog = function(name){
          $log.info(name);
   }
   
 
}]).directive("myDir", function() {
    return {
       template:"<div>"+
                "  <button ng-click='changeAge(info)'>changeAge</button>&nbsp;name:"+
                "  <input type='text' ng-model='name'/>&nbsp;age:"+
                "  <span class='age'>{{age}}</span>"+
                "</div>",
       restrict:"E",
       scope:{
         name:"=",
         age:"@",
         changeAge:"&"
       }
    };
});
    </script>
</body>
</html>



       //html
       <my-dir new-name="info.name" naw-age="{{info.age}}" change-age="changeAge(info)"></my-dir>
       //directive
       scope:{
         name:"=newName",
         age:"@nawAge",
         changeAge:"&"
       }

兩種寫法是相同的

  • @也可以定義在link

.directive("myDir", function() {
    return {
       template:"<div>"+
                "  <button ng-click='changeAge(info)'>changeAge</button>&nbsp;name:"+
                "  <input type='text' ng-model='name'/>&nbsp;age:"+
                "  <span class='age'>{{age}}</span>"+
                "</div>",
       restrict:"E",
       scope:{
         name:"=",
         /*age:"@",*/
         changeAge:"&"
       },
       link:function(scope, iElement, iAttrs){
       	   //scope.age = iAttrs.age; 這么寫 只有在第一次加載的時候等於`scope age`但是不會隨着changeAge事件更新
       	   iAttrs.$observe('age', function(value) {
                   scope.age = value;
                }) 
       }
    };
});

  • 如果用使用&綁定函數傳參數需要json 否則會報錯

TypeError: Cannot use 'in' operator to search for 'editWebsite' in 1


template:"<div>"+
                "  <button ng-click='changeAge({age:age})'>changeAge</button>&nbsp;name:"+
                "  <input type='text' ng-model='name'/>&nbsp;age:"+
                "  <span class='age'>{{age}}</span>"+
                "</div>"

在使用前我們先簡單了解一下下面兩個階段-編譯和鏈接階段

第一個階段是編譯階段,AngularJS會遞歸的遍歷DOM,並從JavaScript中的指令定義知道需要執行的操作。

如圖(from stackoverflow)所示原始DOM模板作為函數的參數傳給compile編譯函數,編譯后會返回它的實例。我們有機會在它被返回前對DOM模板進行操作。

1.1 我們以ng-repeat為例,HTML中生成的重復元素就是DOM模板的實例。實例有多個但是模板元素只有一個。


<body ng-controller="myCtrl">
    <div ng-app="App" ng-controller="Ctrl" class="app">
    <div ng-repeat="info in infoList">
    	<my-dir info ="info"></my-dir>
	</div>
    <script>
    angular.module("App", []).controller("Ctrl", ["$scope",function($scope) {
   
   $scope.infoList = [{
          name:"chenjy",
          age:16
   },{
          name:"tom",
          age:17
   },{
          name:"jerry",
          age:18
   }];
   
  
}]).directive("myDir", function() {
    return {
       template:"<span>{{info.name}}:</span>",
       restrict:"E",
       scope:{
       	  info:"="  
       },
       compile:function(tELe ,tAttrs,transcludeFn){
       	// 對原始DOM模板進行操作
       	tELe.append(angular.element("<span class='age'>{{info.age}}</span>"));
                return{
                        pre:function(scope, iElement, iAttrs, controller){},
                        post:function(scope, iElement, iAttrs, controller){}
                  }
       }
    };
});
    </script>
</body>

第二個階段是鏈接階段,鏈接函數link將模板與作用域鏈接起來。負責設置事件監聽器、監視數據變化和實時的DOM操作。

  • 如果定義了編譯函數compile它會返回pre-linkpost-link函數

  • 如果只定義了鏈接函數link,則會被視為post-link

If you create a directive that only has a link function, AngularJS treats the function as a post-link function. Hence the reason to discuss it here first.

post-link會和前面DOM遍歷相反的順序調用。這個順序保證所有子元素的post-link在父元素post-link運行時都已經被執行了。

  • pre-link是AngularJS提供了一個額外的鈎子。它可以讓你在子元素的post-link函數之前運行你的代碼。

post-link被認為是最安全的,因為此時所有子元素都已經被編譯compile並且所有子元素的pre-linkpost-link都已經執行結束。
所以這里是自定義指令最常用的地方,大多數情況下我們只需要編寫link函數即可


.directive("myDir", function() {
    return {
       template:"<span>{{info.name}}:</span>"+
                "<span class='age'>{{info.age}}</span>",
       restrict:"E",
       compile:function(tELe ,tAttrs,transcludeFn){
                return{
				        // 子元素被鏈接之前執行
                        pre:function(scope, iElement, iAttrs, controller){},
						// 子元素被鏈接之后執行
                        post:function(scope, iElement, iAttrs, controller){
						   // 綁定DOM事件
						   iElement.on('click',function(){                            
       	                    	scope.$apply(function(){                  
       	                    		scope.infoList[0].name += "_";                                
       	                    		scope.infoList[0].age ++;                            
       	                    	});                        
       	                    });
						}
                  }
       }
    };
});
 

等於下面這種寫法


.directive("myDir", function() {
				return {
					template: "<span>{{info.name}}:</span>" +
						"<span class='age'>{{info.age}}</span>",
					restrict: "E",
					link: function(scope, iElement, iAttrs) {
						iElement.on('click', function() {
							scope.$apply(function() {
								scope.infoList[0].name += "_";
								scope.infoList[0].age++;
							});
						});
					}
				};
			});

<body ng-controller="myCtrl">
		<div ng-app="App" ng-controller="Ctrl" class="app">
			<input type="text" focus-me="{{shouldBeFocus}}">
		</div>
		<script>
			angular.module("App", []).controller("Ctrl", function($scope) {
				$scope.shouldBeFocus = true;
			}).directive('focusMe', function() {
				return {
					link: function(scope, element, iAttrs) {
						iAttrs.$observe("focusMe", function(value) {
							element[0].focus();
						});
						element.bind("blur", function() {
							scope.$apply(function() {
								scope.shouldBeFocus = !scope.shouldBeFocus;
							});
						});
					}
				};
			});
		</script>
	</body>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM