AngularJS会触发一些特定的事件,当一个被angular编译过的DOM元素被移除的时候,它会触发一个$destory事件,同样的,当一个angular作用域被移除的时候,它会向下广播$destory事件到所有监听的作用域。
通过监听事件,你可以移除可能引起内存泄露的事件监听器,注册在元素和作用域上的监听器在它们被移除的时候,会自动会清理掉,但是假如注册一个事件在服务或者没有被删除的DOM节点上,你就必须手工清理,否则会有内存泄露的风险。
Best Practice:执行被移除的时候应该做一些清理的操作, 可以使用element.on('$destroy', ...)或者scope.on('$destroy', ...)来运行解除绑定的函数,
创建包裹其他元素的指令
我们现在已经实现了,使用isolate scopes传递数据模型到指令里面。但是有时候我们需要能够传递一整个模板而不是字符串或者对象。让我们通过创建'dialog box'组件来说明。这个'dialog box'组件应该能够包裹任意内容。
要实现这个,我们使用transclude配置
<div ng-controller="Ctrl"> <my-dialog>Check out the contents, {{name}}!</my-dialog> </div>
JS
angular.module('docsTransclusionDirective', []) .controller('Ctrl', function($scope) { $scope.name = 'Tobias'; }) .directive('myDialog', function() { return { restrict: 'E', transclude: true, templateUrl: 'my-dialog.html' }; });
my-dialog.html
<div ng-transclude> </div>
这个transclude配置用来干嘛呢? transclude使带有这个配置的指令的内容能够访问指令外部的作用域。
参照以下例子,注意到我们增加了一个link函数,在这个link函数内部我们重定义了name属性的值为Jeff,那么现在这个{{name}}会被解析成哪个值呢?
<div ng-controller="Ctrl"> <my-dialog>Check out the contents, {{name}}!</my-dialog> </div>
JS
angular.module('docsTransclusionDirective', []) .controller('Ctrl', function($scope) { $scope.name = 'Tobias'; }) .directive('myDialog', function() { return { restrict: 'E', transclude: true, templateUrl: 'my-dialog.html', link: function (element, scope) { scope.name = 'Jeff'; } }; });
my-dialog.html
<div ng-transclude> </div>
一般,我们会认为{{name}}会被解析为Jeff,然而这里,我们看到这个例子中的{{name}}还是被解析成了Tobias.
transclude配置改变了指令相互嵌套的方式,他使指令的内容拥有任何指令外部的作用域,而不是内部的作用域。为了实现这个,它给指令内容一次访问外部作用域的机会。
这样的行为对于包裹内容的指令是非常有意义的。因为如果不这样的话,你就必须分别传入每个你需要使用的数据模型。如果你需要传入每个要使用的数据模型,那么你就无法做到适应各种不同内容的情况。
Best Practice: 仅当你要创建一个包裹任意内容的指令的时候使用transclude:true。
下一步,我们增加一个按钮到'dialog box'组件里面,允许用户使用指令绑定自己定义的行为。
<div ng-controller="Ctrl"> <my-dialog ng-hide="dialogIsHidden" on-close="dialogIsHidden = true"> Check out the contents, {{name}}! </my-dialog> </div>
JS
angular.module('docsIsoFnBindExample', []) .controller('Ctrl', function($scope, $timeout) { $scope.name = 'Tobias'; $scope.hideDialog = function () { $scope.dialogIsHidden = true; $timeout(function () { $scope.dialogIsHidden = false; }, 2000); }; }) .directive('myDialog', function() { return { restrict: 'E', transclude: true, scope: { 'close': '&onClose' }, templateUrl: 'my-dialog-close.html' }; });
my-dialog-close.html
<div> <a href ng-click="close()">×</a> <div ng-transclude></div> </div>
我们想要通过在指令的作用域上调用,来运行我们传递进去的函数,但是这个函数是运行在定义时候的上下文(js通常都是这样子的)。
先前我们看到如何scope配置使用'=prop',但是在上文的例子中,我们使用'&prop','&'绑定开放了一个函数到isolated scope,允许 isolated scope调用它,同时维持原来函数的作用域(这里的作用域都是指$scope)。所以当一个用户点击x时候,就会运行Ctrl控制器的close函数。
Best Practice: 当你的指令想要开放一个API去绑定特定的行为,在scope配置中使用'&prop'.
创建一个添加事件监听器的指令
先前,我们使用link函数创建一个操作DOM元素的指令,基于上面的例子,我们创建一个在元素上添加事件监听的指令。
举个例子,假如我们想要创建一个让用户可拖拽的元素,该怎么做呢?
Drag ME
JS