學(xué)習(xí)《AngularJS深度剖析與實(shí)踐》總結(jié)
- 在我們平時(shí)的開發(fā)中错忱,需要對(duì)某些數(shù)據(jù)進(jìn)行以樹的形式進(jìn)行展現(xiàn)倘待,比如:權(quán)限角色、菜單膝昆、嵌套評(píng)論等丸边。這個(gè)時(shí)候我們需要使用angular進(jìn)行對(duì)數(shù)據(jù)抽象,構(gòu)造我們自己的組件樹:
- 例子:我們就拿主題樹作為一個(gè)例子荚孵,然后一步一步去優(yōu)雅的實(shí)現(xiàn)它:
- 首先我們準(zhǔn)備好angular的庫文件妹窖,建立好相應(yīng)的目錄及文件,按照angular遵循的風(fēng)格:約定優(yōu)于配置收叶。首先我們創(chuàng)建一個(gè)用于展示的目錄骄呼,theme-tree
mkdir theme-tree && cd $_
2.創(chuàng)建需要展示的html頁面文件:
touch index.html
3.創(chuàng)建存放項(xiàng)目js文件的目錄:
mkdir js
4.創(chuàng)建存放angular項(xiàng)目的controller目錄、service目錄和filter目錄:
mkdir controller && mkdir service && mkdir filter
5.創(chuàng)建angular項(xiàng)目的入口文件滔驾,app.js
cd js && touch app.js
6.目前先不考慮UI效果部分谒麦,主要以實(shí)現(xiàn)功能為主,我們使用bower來安裝和管理相應(yīng)的js第三方庫文件哆致,如果沒有安裝bower工具绕德,可以借助npm進(jìn)行安裝-npm install -g bower ,在我們創(chuàng)建的theme-tree目錄下,鍵入如下命令安裝angular庫的依賴:
bower install angular --save
以上命令實(shí)行完畢后我們的目錄結(jié)構(gòu)如下:
7.接下來我們開始編輯js/app.js入口文件:
angular.module('myApp', []);
8.接下來我們開始編寫控制器文件js/controller/index.client.controller.js:
angular.module('myApp').controller("ThreedTreeCtrl",function ThreedTreeCtrl(tree) {
var vm = this;
vm.items = [{
id: 1,
title: "Java",
poster: "Messi",
dateCreated: "2012-02-19T00:00:00",
items: [{
id: 11,
title: 'Spring',
poster: 'John',
dateCreated: "2012-02-19T00:00:00",
items: [
{
id: 111,
title: 'AOP',
poster: 'Mike',
dateCreated: "2016-02-19T00:00:00",
items: [
{
id: 1111,
title: 'IOC',
poster: 'Jack']
}
]
}, {
id: 2,
title: "SpringBoot",
poster: "Lucy",
dateCreated: "2011-02-19T00:00:00"
}
]
}, {
id: 2,
title: "JavaScript",
poster: "Jack",
dateCreated: "2012-02-19T00:00:00",
}
];
});
以上內(nèi)容很簡(jiǎn)單摊阀,構(gòu)建了一個(gè)ThreedTreeCtrl控制器耻蛇,里面嵌套了一些隨意的數(shù)據(jù)踪蹬,主要是為了模擬父子關(guān)系;
9.接下來我們編輯js/service/index.client.service.js文件臣咖,用于對(duì)數(shù)據(jù)進(jìn)行附加相應(yīng)的行為跃捣。思考一下,當(dāng)我們有了這樣一組數(shù)據(jù)后夺蛇,我們要為它添加什么方法和屬性疚漆,首先應(yīng)該添加父節(jié)點(diǎn)是否折疊,此屬性主要是為了在界面顯示的時(shí)候展開或折疊子節(jié)點(diǎn)數(shù)據(jù)刁赦。當(dāng)展開的時(shí)候我們使用“-”表示娶聘,折疊的時(shí)候我們使用"+"表示,當(dāng)折疊時(shí)單擊節(jié)點(diǎn)應(yīng)該展開子節(jié)點(diǎn)甚脉,當(dāng)展開的時(shí)候丸升,單擊子節(jié)點(diǎn)應(yīng)該折疊父節(jié)點(diǎn);將新增的屬性和方法為了減小和原始數(shù)據(jù)沖突牺氨,并且這些數(shù)據(jù)通過$http或者$resource提交給服務(wù)器狡耻,它們所調(diào)用的angular.toJso()函數(shù)會(huì)忽略所有以$開頭的屬性,這樣我們擴(kuò)展的屬性就不會(huì)被提交到服務(wù)端了猴凹。還有一個(gè)方便的是夷狰,當(dāng)我們看到數(shù)據(jù)上有"$"開頭的屬性就是擴(kuò)展的屬性。接下來我們實(shí)現(xiàn)它:
angular.module('myApp').service('tree',function Tree(){
var self = this;
//為每一項(xiàng)節(jié)點(diǎn)添加屬性和方法
var enhanceItem = function(item,childrenName){
item.$hasChildren = function(){
var subItems = this[childrenName];
return angular.isArray(subItems) && subItems.length;
};
item.$foldToggle = function(){
this.$folded = !this.$folded;
};
item.$isFolded = function(){
return this.$folded;
};
};
//對(duì)傳進(jìn)來的數(shù)據(jù)進(jìn)行強(qiáng)化
this.enhance = function(items,childrenName){
if(angular.isUndefined(childrenName)){
childrenName = "items";
}
angular.forEach(items,function(item){
enhanceItem(item,childrenName);
//如果有子節(jié)點(diǎn)則遞歸處理
self.enhance(item[childrenName],childrenName);
});
console.log(items);
return items;
};
});
10.這樣我們完成了對(duì)數(shù)據(jù)進(jìn)行強(qiáng)化精堕,此時(shí)我們?nèi)绻苯釉赾ontroller調(diào)用service的enhance 方法孵淘,將服務(wù)端返回的json數(shù)據(jù)進(jìn)行加強(qiáng),為他們添加的相應(yīng)的屬性和方法歹篓,然后在頁面進(jìn)行展示調(diào)用就可以了瘫证,但是這樣感覺比較臟,不干凈庄撮,我們不在contrller直接調(diào)用service里面的enhance 方法背捌,我們可以創(chuàng)建一個(gè)過濾器來對(duì)數(shù)據(jù)進(jìn)行添加過濾的功能,接下來我們開始編輯filter/index.client.filter.js:
angular.module('myApp').filter('tree',function(tree){
return function(items,childrenName){
tree.enhance(items,childrenName);
return items;
};
});
11.接下來編寫html文件洞斯,開始對(duì)主題樹進(jìn)行展現(xiàn)并且引入相關(guān)文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-app="myApp" ng-controller="ThreedTreeCtrl as vm">
<ul ng-if="vm.items">
<li ng-repeat="item1 in vm.items | tree">
<div ng-click="item1.$foldToggle()">
<span ng-if="item1.$hasChildren()">
<span ng-if="!item1.$isFolded()">-</span>
<span ng-if="item1.$isFolded()">+</span>
</span>
{{ item1.title }}
</div>
<ul ng-if="item1.$hasChildren() && !item1.$isFolded()">
<li ng-repeat="item2 in item1.items">
<div ng-click="item2.$foldToggle()">
<span ng-if="item2.$hasChildren()">
<span ng-if="!item2.$isFolded()">-</span>
<span ng-if="item2.$isFolded()">+</span>
</span>
{{ item2.title }}
</div>
<ul ng-if="item2.$hasChildren() && !item2.$isFolded()">
<li ng-repeat="item3 in item2.items">
{{ item3.title }}
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<script src="bower_components/angular/angular.js"></script>
<script src="js/app.js"></script>
<script src="js/controller/index.client.controller.js"></script>
<script src="js/service/index.client.service.js"></script>
<script src="js/filters/index.client.filter.js"></script>
</body>
</html>
此時(shí)我們便完成了對(duì)主題樹功能的實(shí)現(xiàn)毡庆,在index.html文件中,我們只展示了兩層嵌套關(guān)系以作為示例烙如,根據(jù)自己的業(yè)務(wù)場(chǎng)景進(jìn)行擴(kuò)展么抗。
以上實(shí)現(xiàn)還不夠優(yōu)雅,等待以后需要將主題遞歸樹封裝為指令亚铁,最后附上github地址:
https://github.com/strongant/angularjs
源碼位于此倉庫下的angular-tree目錄蝇刀,歡迎提出issue。