AngularJS中transclude用法详解

Transclude - 在Angular的指令中,大家会看到有一个这样的一个配置属性,这个单词在英文字典里面也查询不到真实的意思,所以就用英文来标示它吧。如果你深入的使用angular的话,你就花很大一部分时间来创建自定义指令,那么就不可避免的要深入理解transclude。简单的讲,transclude主要完成以下工作,取出自定义指令中的内容(就是写在指令里面的子元素),以正确的作用域解析它,然后再放回指令模板中标记的位置(通常是ng-transclude标记的地方),虽然使用内建的ngTransclude对于基本的transclude操作已经足够简单,但是在文档中对这个transclude的解释还是有存在很多疑惑,比如说:

在compile函数中接收到了一个叫transclude的参数是什么东西呢?有什么用呢?

在控制器中也有个叫$transclude的可以通过依赖注入的服务,这又是什么呢?

隔离作用域跟transclude有什么关系?

属性的transclude操作

接下来我们将一个个的解释:

基本的transclude

我们通过一个基本的transclude例子来讲解吧,我们现在要创建的是一个叫buttonBar的指令,用户可以通过它来添加一组button到页面上,这个指令会对不同的button进行位置的排列。以下例子css样式是使用Bootstrap框架。

在fiddle中查看例子:

<div ng-controller="parentController"> <button-bar> <button ng-click="onPrimary1Click()">{{primary1Label}}</button> <button>Primary2</button> </button-bar> </div>

JS:

var testapp = angular.module('testapp', []); testapp.controller('parentController', ['$scope', '$window', function($scope, $window) { console.log('parentController scope id = ', $scope.$id); $scope.primary1Label = 'Prime1'; $scope.onPrimary1Click = function() { $window.alert('Primary1 clicked'); }; }]); testapp.directive('primary', function() { return { restrict: 'C', link: function(scope, element, attrs) { element.addClass('btn btn-primary'); } } }); testapp.directive('buttonBar', function() { return { restrict: 'EA', template: '<div><div ng-transclude></div></div>', replace: true, transclude: true }; });

我们先看下HTML标签,buttonBar指令包裹着几个button元素。而button元素也被链接上了基于class的primary指令,不要太在意这个primary指令的功能它只不过为button元素添加一些css的样式而已。现在我们来看buttonBar指令,它提供了一个transclude:true属性,同时在它的模板里面使用ng-transclude指令。在运行的过程中,Angular获取到自定义指令的内容,处理完了之后把结果放到了模板中链接上ng-transclude的div。

transclude到多个位置

现在我们来增强下我们的buttonBar指令的功能,我们增加了两种按钮,primary和secondary,其中primary按钮是排右边,secondary是排左边。所以要做到这个功能,它必须能够取出指令的内容,然后把它们分别添加到不同的div中,一个用来放primary按钮, 一个用来放secondary按钮。

这样的话,默认的机制已经满足不了我们的要求,于是我们有了另外一种方法:

设置transclude为true

手工移动button元素到合适的div

最后,在指令的编译或链接函数中移除原始的用来transclude操作的元素

这种方法就是先把所有的内容插入到ng-transclude标记的元素中,然后在link函数中再找出元素的插入的元素,重新放到元素的其他地方,最后删除原来暂存内容的元素。

在fiddle中查看例子:

<div ng-controller="parentController"> <button-bar> <button ng-click="onPrimary1Click()">{{primary1Label}}</button> <button>Primary2</button> <button>Secondary1</button> </button-bar> </div>

JS:

var testapp = angular.module('testapp', []); testapp.controller('parentController', ['$scope', '$window',function($scope, $window) { $scope.primary1Label = 'Prime1'; $scope.onPrimary1Click = function() { $window.alert('Primary 1 clicked'); } }]); testapp.directive('primary', function() { return { restrict: 'C', link: function(scope, element, attrs) { element.addClass('btn btn-primary'); } } }); testapp.directive('secondary', function() { return { restrict: 'C', link: function(scope, element, attrs) { element.addClass('btn'); } } }); testapp.directive('buttonBar', function() { return { restrict: 'EA', template: '<div><div></div><div></div><div ng-transclude></div></div>', replace: true, transclude: true, link: function(scope, element, attrs) { var primaryBlock = element.find('div.primary-block'); var secondaryBlock = element.find('div.secondary-block'); var transcludedBlock = element.find('div.transcluded'); var transcludedButtons = transcludedBlock.children().filter(':button'); angular.forEach(transcludedButtons, function(elem) { if (angular.element(elem).hasClass('primary')) { primaryBlock.append(elem); } else if (angular.element(elem).hasClass('secondary')) { secondaryBlock.append(elem); } }); transcludedBlock.remove(); } }; });

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzgzgz.html