看了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,會報錯