新手如何简单理解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,会报错
在这里插入图片描述

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