Angular中實現樹形結構視圖執行個體代碼,angular樹形

來源:互聯網
上載者:User

Angular中實現樹形結構視圖執行個體代碼,angular樹形

近兩年當中使用Angular開發過很多項目,其中也涉及到一些樹形結構視圖的顯示,最近的在項目中封裝了大量的組件,一些組件也有樹形結構的展示,所以寫出來總結一下。

相信大家都知道,樹結構最典型的例子就是目錄結構了吧,一個目錄可以包含很多子目錄,子目錄又可以包含若干個子孫目錄,那咱們今天就以目錄結構為例來說明一下Angular中樹結構的實現。

首先,我們希望封裝一個組件,用於顯示整個目錄的樹形機構,代碼如下:

<!DOCTYPE html> <html ng-app="treeDemo">  <body>   <div ng-controller="TreeController">     <folder-tree current-folder="folder"></folder-tree>   </div>   <script src="node_modules/angular/angular.min.js"></script>   <script src="js/app.js"></script>  </body> </html> 

就像上面的代碼一樣,我們直接聲明folder-tree標籤,將controller中的folder資料作為參數傳遞進去,預期會顯示出一個完整的樹狀目錄結構。接下來我們就來定義模組,控制器,以及相應的指令部分:

angular.module('treeDemo', [])  .controller("TreeController", function($scope) {   $scope.folder = {     name: 'techs',     children: [       {         name: 'server-side',         children: [           {             name: 'Java'           },           {             name: 'Python'           },           {             name: 'Node'           }         ]       },       {         name: 'front-end',         children: [           {             name: 'jQuery'           },           {             name: 'Angular'           },           {             name: 'React'           }         ]       }     ]   }  })  .directive("folderTree", function() {   return {     restrict: "E",     scope: {       currentFolder: '='     },     templateUrl: 'template/tree.html'   };  }); 

如上所述,在控制器中我們在$scope中綁定了一個folder的資料對象,包含整個的目錄結構資料,接著定義了folderTree指令,它會使用tree.html作為模板進行視圖渲染,我們這就來look look模板中的內容:

<p>{{currentFolder.name}}</p> <ul>   <li ng-repeat="subfolder in currentFolder.children">     <folder-tree current-folder="subfolder"></folder-tree>   </li> </ul> 

可以看到,在模板中有個很重要的環節,那就是使用ng-repeat指令遍曆目前的目錄的子集,然後再次使用folder-tree組件來渲染相應的子目錄,這種方式簡直是完美,現在我們來看看渲染的結果:

這種在模板中嵌套使用指令的方法很完美,只可惜低版本的Angular中是無法實現的,會出現無限遞迴迴圈,造成頁面假死,這是Angular本身的解析機製造成的。經測試,Angular 1.5.0及以上版本是沒有問題的,但在Angular 1.4.9及以下版本中就會運行失敗。假如你在項目中真的使用了低版本的Angular並且造成運行失敗,我們還可以稍微改動一下模板,採用ng-include來實現同樣的功能:

<p>{{currentFolder.name}}</p> <ul>   <li ng-repeat="subfolder in currentFolder.children"      ng-include="'template/tree.html'"      ng-init="currentFolder = subfolder">   </li> </ul> 

我們在模板中去掉了folder-tree指令,使用了ng-include指令,再次將tree.html模板引入進來,需要注意的是,因為ng-include會建立一個獨立的範圍,為了讓其正確的引用到currentFolder變數,我們需要在每個ng-include中初始化currentFolder,將其賦值為ng-repeat中的當前subfolder,另外,別忘了ng-include指令中模板路徑前後加上單引號。

這樣確實可以,但是你可能覺得有些遺憾,沒能使用最好的解決方案來實現這個樹結構。

其實這個問題早就有人吐槽了,令人驚喜的是,有個叫Mark的夥計寫了一個service專門解決這個問題:

/*  * An Angular service which helps with creating recursive directives.  * @author Mark Lagendijk  * @license MIT  */ angular.module('RecursionHelper', []).factory('RecursionHelper', ['$compile', function($compile){   return {     /**      * Manually compiles the element, fixing the recursion loop.      * @param element      * @param [link] A post-link function, or an object with function(s) registered via pre and post properties.      * @returns An object containing the linking functions.      */     compile: function(element, link){       // Normalize the link parameter       // 如果link參數是物件類型link:{pre: function(...){}, post: function(...){}}則不做處理       // 如果link參數是函數類型則將其作為post-link函數在$compile之後調用       if(angular.isFunction(link)){         link = { post: link };       }        // Break the recursion loop by removing the contents       // 擷取並清空當前元素的內容,後面進行編譯       var contents = element.contents().remove();       var compiledContents;        return {         pre: (link && link.pre) ? link.pre : null,         /**          * Compiles and re-adds the contents          * 編譯和重新新增內容到當前元素          */         post: function(scope, element){           // Compile the contents           if(!compiledContents){             compiledContents = $compile(contents);           }           // Re-add the compiled contents to the element           compiledContents(scope, function(clone){             element.append(clone);           });            // Call the post-linking function, if any           if(link && link.post){             link.post.apply(null, arguments);           }         }       };     }   }; }]); 

現在我們只需引入這個模組,然後在directive中使用RecursionHelper這個service,調用其compile手動編譯指令對應的元素節點:

angular.module('treeDemo', ['RecursionHelper'])  .controller("TreeController", function($scope) {   $scope.folder = {     name: 'techs',     children: [       {         name: 'server-side',         children: [           {             name: 'Java'           },           {             name: 'Python'           },           {             name: 'Node'           }         ]       },       {         name: 'front-end',         children: [           {             name: 'jQuery'           },           {             name: 'Angular'           },           {             name: 'React'           }         ]       }     ]   }  })  .directive("folderTree", function(RecursionHelper) {   return {     restrict: "E",     scope: {       currentFolder: '='     },     templateUrl: 'template/tree.html',     compile: function(element) {       // 我們這裡使用RecursionHelper的compile方法編譯指令當前元素,這裡第二個參數指定一個函數,相當於常用的link函數       // 當然我們也可以指定一個對象,裡麵包含pre和post函數,分別對應pre-link和post-link       return RecursionHelper.compile(element, function(scope, iElement, iAttrs, controller, transcludeFn){         // Define your normal link function here.         // Alternative: instead of passing a function,         // you can also pass an object with          // a 'pre'- and 'post'-link function.          // 這裡可以往scope中綁定一些變數         scope.variable = 'hello world';       });     }   };  }); 

在上面代碼中,我們在建立treeDemo模組時引入RecursionHelper模組,然後在建立folderTree指令時使用RecursionHelper服務,並且在compile方法中調用RecursionHelper的compile方法,即可修複上面的問題。

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.