- 在自定义指令时,如果将scope属性值设置为true,则可以创建了一个隔离式的子作用域。
- scope属性值还可以设置成一个JSON对象,如果是对象,那么,父作用域与子作用域是完全独立的,不存在任何关联。
当指令中的scope属性值是JSON对象时
- 如果子作用域需要添加属性,必须先添加指令中的link函数,然后,通过函数中的scope对象进行添加;
- 如果在子作用域中,要绑定或调用父作用域中的属性和方法,则需要在scope属性对应的JSON对象值中添加绑定策略。
严格来说,在JSON对象中添加的有3种绑定策略,分别是“@绑定”、“=绑定”和“&=绑定”,它们绑定的符号不同,执行的功能也是有区别的。
- @绑定
“@绑定”的功能与将scope属性设置为true时有许多相同的地方。表现为:在子作用域重置属性内容之前,父作用域的属性内容修改了,子作用域对应的属性内容也会随之修改,并且子作用的属性内容变化时,不会影响到父作用域中对应的属性内容,这是两者的相同之处。
两者唯一的不同之处在于,“@绑定”的功能在子作用域中重置属性内容之后,再返回修改父作用域中对应属性内容时,子作用域对应的属性内容同样还会随之修改。如果将scope属性设置为true,这种子作用域随父作用域变化而变化的情况只发生在子作用域重置属性内容之前,重置之后则不会随之变化,在使用时必须要注意。 - =绑定
“=绑定”的功能是创建一个父与子作用域可以同时共享的属性,即当父作用域修改了该属性,子作用域也随之变化;子作用域重置时,父作用域也会跟随变化,两个作用域之间的属性内容是互通的,是完全共享和同步的。 - &绑定
“&绑定”的功能是可以在独立的子作用域中直接调用父作用域的方法。在调用时可以向函数传递实参数,这种功能的好处在于,避免重复编写功能相同的代码,只需要进行简单的绑定设置,就可以使指令执行后,轻松调用元素控制器中的方法。
示例 通过一个实例来展示scope属性是JSON对象的过程
- 功能描述
自定义一个名称为“tsJson”的指令,在定义的过程中将scope属性值设置为JSON对象。在对象中,使用不同的策略绑定3个不同的属性,并在单击“重置”按钮时,重置子作用域中的属性值,并执行父作用域中的函数。 - 实现代码
<!DOCTYPE html>
<html ng-app="a8_7">
<head>
<title>scope属性是JSON对象</title>
<script src="/node_modules/angular/angular.min.js"></script>
<style type="text/css">
.frame {
padding: 2px 8px;
margin: 0px;
font-size: 12px;
width: 320px;
background-color: #eee;
}
.tip {
font-size: 9px;
color: #666;
margin: 3px 0px;
padding: 5px 0px;
}
</style>
<script type="text/ng-template" id="tpl">
<div class="tip">
<span>姓名:{{textName}}</span>
<span>年龄:{{textAge}}</span>
</div>
<button ng-transclude></button>
</script>
</head>
<body>
<div class="frame" ng-controller="c8_7">
姓名:<input ng-model="text_name"
placeholder="请输入姓名" /><br />
年龄:<input ng-model="text_age"
placeholder="请输入年龄" />
<div class="tip">{{tip}}</div>
<ts-json a-attr="{{text_name}}" b-attr="text_age" reset="reSet({name:text_name})">重置</ts-json>
</div>
<script type="text/javascript">
var app = angular.module('a8_7', [])
.controller('c8_7', function ($scope) {
$scope.reSet = function (type) {
$scope.tip = "姓名与年龄重置成功!"+ "[" + type.type+"]" + JSON.stringify(type);
}
})
.directive('tsJson', function () {
return {
restrict: 'EAC',
templateUrl: 'tpl',
transclude: true,
scope: {
// @父作用域修改会改变子作用域,子作用域修改不会改变父作用域
//@在子作用域重置后,再修改父作用域内容,子作用域还会修改
//scope属性设置为true时,子作用域重置后,再修改父作用域内容,子作用域不会修改
//绑定属性值的方式为{{}}
textName: '@aAttr',
/**
* =父子作用域完全共享,同步
* 绑定属性值方式为=
*/
textAge: '=bAttr',
/*
* &绑定:可以在子作用域中直接调用父作用域中的方法,可以向函数传递实参
* 父级作用域绑定 通过&符号可以对父级作用域进行绑定,以便在其中运行函数。
* 意味着对这个值进行设置时会生成一个指向父级作用域的包装函数。
* 要使调用带有一个参数的父方法,我们需要传递一个对象,这个对象的键是参数的名称,值 是要传递给参数的内容。
*/
reSet: '&reset'
},
link: function (scope, iEle, iAttrs) {
iEle.bind('click', function () {
scope.$apply(function () {
scope.reSet();
scope.textName = '张三';
scope.textAge = '20';
})
})
}
};
});
</script>
</body>
</html>
-
运行结果
单击重置前子作用域随父作用域的改变而改变
单击“重置”按钮子作用域属性值发生变化,并执行父作用域中的reset方法,并向方法传递参数 -
源码分析
- 定义名称为“tsJson”的指令时,首先,添加JSON对象型的“scope”属性。
- 先在指令元素中创建“a-attr”或“b-attr”的属性,由于HTML不区分大小写,因此,在定义属性名时,不使用驼峰写法,而改用“-”隔开形式;
- 然后,在“scope”值中对创建的属性按策略进行绑定,在绑定过程中,策略符后面修改成对应的驼峰写法,如属性名称为“a-attr”,采用第一种策略绑定时,则写成“@aAttr”;最后,在“scope”值中绑定后的属性,就可以在link函数中使用了。
- 当单击“重置”按钮时,触发link函数中绑定的“click”事件。在事件中,先执行策略绑定的父作用域的reSet方法,并重置子作用域中名为“textName”和“textAge”两个属性
- 由于这两个属性与父作用域绑定的策略不同,前者是“@绑定”后者是“=绑定”,因此,当“textAge”属性值修改后,对应的父作用域中对应的值也随之修改。
Tips:
绑定策略不同,在指令元素中,属性绑定属性值也会有些变化
- “@绑定”方式绑定的属性,绑定属性值的方式为双大括号“{{}}”
- 而使用“=绑定”方式绑定的属性,绑定属性值的方式为“=”等号