angular指令的transclude屬性是一個讓初學者比較難以理解的地方,transclude能夠設置爲false(默認),true或者對象三種值,若是不設該屬性就默認爲false,也就是說你不須要將該指令所在元素包含的內容嵌入到模板中。html
當transclude爲true的時候,這時指令所在元素包含的內容會被嵌入到模板中有ng-transclude指令的元素中,例如:node
index.htmlapp
<!DOCTYPE html> <html ng-app="myapp"> <head> <meta charset="utf-8"> <title>angular test</title> </head> <body ng-controller="myCtrl"> <div hello="{{name}}">你好</div> </body> <script src="./node_modules/angular/angular.js"></script> <script src="./index.js"></script> </html>
index.js函數
let app = angular.module('myapp',[]); app.controller('myCtrl', $scope =>{ $scope.name = "Jhon"; }); app.directive('hello', () =>{ return { restrict: 'A', template: '<div><span ng-transclude></span>{{name}}</div>', transclude: true, scope:{ name: "@hello" } } });
運行以後的效果以下:spa
<div hello="Jhon" class="ng-isolate-scope"> <div class="ng-binding"> <span ng-transclude="">你好</span> Jhon </div> </div>
當指令元素包含的內容須要嵌入到指令模板不一樣地方的時候,這個時候就要把transclude設置爲對象,例以下面這個我在項目中使用的一個例子:rest
index.htmlcode
<!DOCTYPE html> <html ng-app="myapp"> <head> <meta charset="utf-8"> <title>angular test</title> </head> <body ng-controller="myCtrl"> <panel> <panel-header>{{title}}</panel-header> <panel-body>{{content}}</panel-body> <panel-footer>{{footer}}</panel-footer> </panel> </body> <script src="./node_modules/angular/angular.js"></script> <script src="./index.js"></script> </html>
index.jshtm
let app = angular.module('myapp',[]); app.controller('myCtrl', ['$scope', $scope =>{ $scope.title = "標題"; $scope.content = "內容"; $scope.footer = "頁腳"; }]); app.directive('panel', () =>{ return { restrict: 'E', replace: true, transclude: { 'header': '?panelHeader', 'body': 'panelBody', 'footer': '?panelFooter' }, template: ` <div class="panel"> <div class="panel-header" ng-transclude="header"></div> <div class="panel-body" ng-transclude="body"></div> <div class="panel-footer" ng-transclude="footer"></div> </div>` } });
顯示結果以下:對象
<div class="panel"> <div class="panel-header" ng-transclude="header"> <panel-header class="ng-binding ng-scope"> 標題 </panel-header> </div> <div class="panel-body" ng-transclude="body"> <panel-body class="ng-binding ng-scope"> 內容 </panel-body> </div> <div class="panel-footer" ng-transclude="footer"> <panel-footer class="ng-binding ng-scope"> 頁腳 </panel-footer> </div> </div>
這裏指令元素內部有三個指令,這三個指令必須以E的形式調用,它們分別要插入到模板的不一樣位置,tranclude指定了要插入的位置,transclude是一個鍵值對的對象,key指定了要插入模板的位置,value就是要插入的內容,?表明這個嵌入點不必定有指令存在,不然必須在這個點插入指令,否則會報錯。blog
值得注意的是,這個實例也證實了一點,指令包含的元素的做用域繼承自指令的父做用域而不是隔離做用域。
除了使用ng-transclude指令指定內容嵌入的地方外,咱們還有兩種方法能夠作到這點。
第一種就是在控制器中使用$transclude服務,例如如下代碼:
index.html
<!DOCTYPE html> <html ng-app="myapp"> <head> <meta charset="utf-8"> <title>angular test</title> </head> <body ng-controller="myCtrl"> <hello name="{{name}}"><span>{{action}}</span></hello> </body> <script src="./node_modules/angular/angular.js"></script> <script src="./index.js"></script> </html>
index.js
let app = angular.module('myapp',[]); app.controller('myCtrl', ['$scope', $scope =>{ $scope.name = "Jhon"; $scope.action = "你好"; }]); app.directive('hello', () =>{ return { restrict: 'E', transclude: true, controller: ['$scope', '$element', '$transclude', ($scope, $element, $transclude) =>{ $transclude(clone =>{ //$element.find只能經過標籤名進行查找 $element.find('span').append(clone); }); }], template: '<div><span></span>{{name}}</div>', scope: { name: '@' } } });
最後顯示的結果以下:
<hello name="Jhon" class="ng-isolate-scope"> <div class="ng-binding"> <span> <span class="ng-binding ng-scope"> 你好 </span> </span> Jhon </div> </hello>
其中控制器中的$element就是編譯了以後的模板,而$transclude中的參數clone則是被編譯了的指令包含的內容。二者能夠同時對模板和內容進行處理。
另外一種方法是在compile中指定第三個transcludeFn參數,以下所示:
index.js
let app = angular.module('myapp',[]); app.controller('myCtrl', ['$scope', $scope =>{ $scope.name = "Jhon"; $scope.action = "你好"; }]); app.directive('hello', () =>{ return { restrict: 'E', transclude: true, compile: (tElement, tAttrs, transcludeFn) =>{ return (scope, element, attrs) =>{ scope.action = "hello"; transcludeFn(scope, (clone) =>{ element.find('span').append(clone); }); }; }, template: '<div><span></span>{{name}}</div>', scope: { name: '@' } } });
這個文件實現了以上控制器中相同的功能,transcludeFn接受兩個參數,一個scope做用域,一個函數,和controller同樣,這個函數的參數clone就是編譯以後的要嵌入的內容。惟一不一樣的是,編譯這個clone的做用域是傳進去的第一個參數,而controller中clone是繼承了指令的父做用域。