新手如何簡單理解directive的scope

看了angular的菜鳥教程和官方教程,覺得不是特別夠用,作爲新手就算理解了1+1=2,但在計算稍微複雜點的公式(場景或者需求)時,中間依舊有斷隔。
爲了加深記憶,對於不理解之處,自己在新人的角度做個測試記錄說明一下。
所有分割線的論證部分如果不想看,可快速翻閱跳過

1、測試自定義指令內部運行的順序

得出結果:區域1 > 區域2 > 區域3 > 區域4

代碼書寫順序如下

function($compile){
	//區域1,這個地方通常用來生成dom,直接給下面的template賦值
	return {
		scope:false,
		template:function(){
			//區域2,也能生成dom
			return dom;
		},
		//處理數據和事件
		controller:function($scope){
			//區域3
		},
		//處理數據、事件,並且渲染模板
		link:function(scope, ele,attr){
			//區域4
		}
	}
}

執行順序 和書寫順序 一致,後面常用到這幾個區域。

--------------------------------------------------- 測試代碼1 --------------------------------------------

//html
<div myDrfunc item="nowItem" site='mesWebsite'></div>

//javascript
app.controller('ctrl', function(){}).directive('myDr', ['$compile', myDrfunc]);

function myDrfunc($scope, $compile){
	console.log('指令before return', '加載指令模板生成邏輯區');
	var controller = ['$scope', function controller($scope){
		console.log('controller區域');
	}];
	var link = function(scope,ele,attr){
			console.log('指令link區域');
	}
	return {
		scope:true, 
		restrict:'AE',
		controller:controller,
		template:function(){
			console.log('模板生成');
		},
		link:link
	}
}

以上運行結果爲
在這裏插入圖片描述
執行結果是:

before return > return template > return controller > return link

------------------------------------------------------- end 測試代碼1 -------------------------------------

2、使用在template裏的變量是directive自己的作用域

template裏的變量是directive自己的!自己的!自己的!名字可以隨便取。

因爲看了很多教程,誤以爲dom裏面用的都是父級$scope的變量啊。弱化了directive的作用域的存在。

雖然總是說directive有自己的scope,但認爲是使用了父級scope(scope:false/true),就寫成父級scope的變量名,其實是跳了一層理解的,兩個概念混在了一起,彷佛沒有體現自己有scope的價值嘛。

主要在使用的時候會搞混。作爲新人,上面的關於scope的說法可能不嚴謹,但我其實就是想知道在區域1生成dom的時候,爲啥console.log(父級變量)都是undefined。

曲線救國,直到開始使用了隔離作用域scope:{ }。突然恍然大悟。

我認爲scope的理解可以先從隔離作用域開始,以強調directive有自己的scope作用域的設定。

理解directive有自己的作用域

1、scope:{ }生成隔離作用域時
1.1 寫起來怪彆扭?如何理解在html頁面和js代碼裏都要綁定在同一個屬性上

剛開始因爲它這個scope的寫法挺繞的,父級變量綁定在屬性上,自己的變量也要跟屬性綁一起。

它做的是一個等價的事情,可以這麼理解(不考慮是否雙綁的情況),比如

//實際等價要這樣
function getNum(num){
	return val = num;
}

<div ny-directive num="x"></div>

//num="x"相當於把x賦予num爲默認值

num = function getNum(num=x){
	return val = num;
}

<div ny-directive num="y"></div>

//num="y"相當於把y賦予num爲默認值

num = function getNum(num=y){
	return val = num;
}

是個賦值默認值的過程,下面是調用。

當確定scope時調用函數。

scope:{  
	'val':'=num',   //調用num(),返回val值
}
1.2 scope有自己作用域的變量,也拿不到父級的變量

除非通過屬性一個個賦值。

既然是隔離作用域,我就要自己取名,不要和父級一樣,給directive設定兩個變量myItem,mySite,分別由父級nowItem,mesWebsite綁定而來。

那就將四個變量都打印在區域1-4,來看看能拿到那些變量的值。

--------------------------------------------------- start 測試代碼2 ---------------------------------------------------

//打印部分1,改名前後的變量都打出來,爲節省代碼長度,用註釋文字代替
console.log('nowItem', $scope.nowItem);  //父級
console.log('mesWebsite', $scope.mesWebsite); //父級
console.log('myItem', $scope.myItem);  //自己的
console.log('mySite', $scope.mySite);  //自己的

除了link函數使用scope調用,其他地方全是用$scope調用。

//html

<div myDrfunc item="nowItem" site='mesWebsite'></div>

//js
//父級設定3個變量
 app.controller('Ctrl', function($scope) {
 	$scope.menu = {
 		'菜單1':{"name":"菜單1","mestype":3},
 		'菜單2':{"name":"菜單2","mestype":1}
 	};
   $scope.nowItem = {
     name: '菜單1',
     mestype: 3
   };
   $scope.mesWebsite = '123456';
 })
 .directive('myDr', ['$compile', myDrFunc]);  //myDr裏的$scope不用專門注入
 
function myDrFunc($scope){
	var dom = '<div>我是自定義部分</div>';
	console.log('指令before return', '加載指令模板生成邏輯區');
	//打印部分1 打在這兒----------------
	var controller = ['$scope', function controller($scope){
			console.log('指令controller區域');
			//打印部分1 打在這兒------------
	}];
	var link = function(scope,ele,attr){
		console.log('指令link區域');
		//打印部分1 打在這兒-----------------------
	}
	
	return {
		//【myItem】和【item】如果想取名稱一致,寫成{'item':'='}即可
		scope:{  //書寫的時候雙邊都要加引號			
			'myItem':'=item', //myItem變量綁定item屬性
			'mySite':'=site'  //mySite變量綁定site
		},
		restrict:'AE',
		controller:controller,
		template:function(){
			console.log('模板生成');
			//打印部分1 打在這兒-------------------
			return dom;
		},
		link:link
	}
}

打印結果如下(看3和4)
在這裏插入圖片描述

---------------------------------------------------------------- end 測試代碼2 ------------------------------------

可以看到區域3和4取不到(父級的)nowItem和mesWebsite了,只能獲取到自己新增的myItem和mySite。

這裏寫在scope:{ }裏的就是directive自己的,沒寫的就拿不到。

重複使用

directive內部寫法是固定的,可由唯一屬性調用。而外部綁定由html其他屬性值來確定的,可以變化多端。也就是說,如果複用指令,自己單個變量可以綁定多個父級變量。

//以上例子是,site就像個形參

<div myDrfunc item="nowItem" site='mesWebsite'></div>
or
<div myDrfunc item="nowItem" site='menu'></div>

//還有可能是,color就像個形參

<div myDrfunc item="nowItem" color='color1'></div>
or
<div myDrfunc item="nowItem" color='color2'></div>

mySite的值綁定的父級變量就可以是多個了。

1.3 =,@,&的用法簡單介紹及注意。
@:單向綁定,外部scope能夠影響內部scope,但反過來不成立

=:雙向綁定,外部scope和內部scope的model能夠相互改變 

&:把內部scope的函數的返回值和外部scope的任何屬性綁定起來

格式要求’:‘雙邊都要加引號

//綁定屬性
my-item = "xxxx"

//scope, 兩種寫法
scope:{
  'myItem':'=',  
  'item':'=myItem'
}

使用‘@’時候,屬性使用{{}}表達式,單向綁定直接獲取的值

//綁定屬性
my-item = "{{xxxx}}"

//scope,兩種寫法
scope:{
  'myItem':'@', 
  'item':'@myItem'
}

還沒有使用過&,之後再補充。

2、scope:true
2.1 先來看下各個父級變量在directive裏各區域存在的情況

結論:只有controller和link裏能拿到數據,其他地方都拿不到。

-------------------------------------------------------------- start 測試代碼3 ------------------------------------------------

跟上面一樣,父級給了3個變量,全部打印在區域1-4的位置。

//打印部分2
console.log('$scope.menu', $scope.menu);
console.log('$scope.nowItem', $scope.nowItem);
console.log('$scope.mesWebsite', $scope.mesWebsite);

除了link函數使用scope調用,其他地方全是用$scope調用。

//html

<div myDrfunc item="nowItem" site='mesWebsite'></div>

//js
//設定3個變量
 app.controller('Ctrl', function($scope) {
 	$scope.menu = {
 		'菜單1':{"name":"菜單1","mestype":3},
 		'菜單2':{"name":"菜單2","mestype":1}
 	};
   $scope.nowItem = {
     name: '菜單1',
     mestype: 2
   };
   $scope.mesWebsite = '123456';
 })
 .directive('myDr', ['$compile', myDrFunc]);  //myDr裏的$scope不用專門注入

function myDrFunc($scope){
	var dom = '<div>我是自定義部分</div>';
	console.log('指令before return', '加載指令模板生成邏輯區');
	//打印部分2 打在這兒-----------------
	var controller = ['$scope', function controller($scope){
			console.log('指令controller區域');
			//打印部分2 打在這兒------------------
	}];
	var link = function(scope,ele,attr){
		console.log('指令link區域');
		//打印部分2 打在這兒----------------------
	}
	
	return {
		scope:true,    //繼承了父級的scope, 能讀取父級的數據和事件
		restrict:'AE',
		controller:controller,
		template:function(){
			console.log('模板生成');
			//打印部分2 打在這兒---------------------
			return dom;
		},
		link:link
	}
}

顯示

controller和link能拿到這些數據,而區域1和2永遠拿不到這些數據

在這裏插入圖片描述

---------------------------------------------------------------------- end 測試代碼3 --------------------------------

2.2 先有繼承,然後有能力改變什麼後從此就獨立什麼,成長系

因爲scope:true表示繼承父級的scope,這個繼承和函數的繼承是一樣的,子作用域的原型鏈上有父級的作用域。

直接訪問的方式會訪問原型鏈上的父級作用域
在這裏插入圖片描述
而賦值的方式則會創建一個自己的作用域變量。

直到開始修改子輸入框後(賦值的方式),子輸入框就長大了。
在這裏插入圖片描述
孩子scope裏的input就從父級被創建並繼承了過來,屬於自己的私人小件啦,可以自己隨便改。

而私人的物件父親是從來不過問的,因爲對他沒有任何影響。

如綁定多層數據的屬性,會出現scope:true失敗的情況,查看【傳送門:angular+directive+scope:true修改規則對多層數據無效,主要受原型鏈影響】

3:scope:false

沒啥寫的啦,看圖吧!
在這裏插入圖片描述
在這裏插入圖片描述
注意:

directive不需要顯示注入專門$scope,會報錯
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章