通過(guò)AngularJS仿豆瓣一刻的案例:https://github.com/zhongxiaolian/douban
AngularJS介紹
AngularJS是一款由Google公司開(kāi)發(fā)維護(hù)的前端MVC框架,其克服了HTML在構(gòu)建應(yīng)用上的諸多不足,從而降低了開(kāi)發(fā)成本提高了開(kāi)發(fā)效率。
AngularJS和jQuery是有一定區(qū)別的,jQuery更準(zhǔn)確的來(lái)說(shuō)只是一個(gè)類(lèi)庫(kù)(類(lèi)庫(kù)指的是一系列函數(shù)的集合)以DOM作為驅(qū)動(dòng),而AngularJS則是一個(gè)框架(諸多類(lèi)庫(kù)的集合)以數(shù)據(jù)和邏輯作為驅(qū)動(dòng)。
框架對(duì)開(kāi)發(fā)的流程和模式做了約束,開(kāi)發(fā)者需要遵照約束進(jìn)行開(kāi)發(fā),更注重實(shí)際的業(yè)務(wù)邏輯。
MVC
在開(kāi)始學(xué)習(xí)AngularJS之前需要先了解什么是MVC。它不是一種技術(shù),而是一種開(kāi)發(fā)模式,更準(zhǔn)確的說(shuō)是組織代碼結(jié)構(gòu)的方式,廣泛應(yīng)用于軟件開(kāi)發(fā)領(lǐng)域,更多應(yīng)用在后端開(kāi)發(fā)程序里,在最初的前端開(kāi)發(fā)的過(guò)程中js,css,html混在一起,代碼的結(jié)構(gòu)十分混亂,而且代碼之間的耦合度比較高,不利于后期代碼的維護(hù),后來(lái)被引入到前端開(kāi)發(fā)中,由于受到前端技術(shù)的限制便有了一些調(diào)整,進(jìn)而出現(xiàn)了很多MVC的衍生版(子集)如MVVM、MVW、MVP、MV*等。
MVC由模型(Model)、視圖(View)、控制器(Controller)3部分構(gòu)成,采用這種開(kāi)發(fā)模式為合理組織代碼、降低代碼間耦合度提供了方便。
模型:一般用來(lái)處理數(shù)據(jù),一般指操作數(shù)據(jù)庫(kù)。
視圖:一般用來(lái)展示數(shù)據(jù),比如通過(guò)HTML展示。
控制器:一般用做連接模型和視圖的橋梁。
接下來(lái)就該進(jìn)入正題了。。。。。
模塊化
使用AngularJS構(gòu)建應(yīng)用(APP)時(shí)是以模塊化(module)的方式組織的,即將整個(gè)應(yīng)用劃分為若干個(gè)模塊,每個(gè)模塊都有各自的職責(zé),最終組合成一個(gè)整體。
采用模塊化的組織方式可以最大程度的實(shí)現(xiàn)代碼的復(fù)用,可以像搭積木一樣進(jìn)行開(kāi)發(fā)。
-
定義應(yīng)用
通過(guò)為任一個(gè)HTML標(biāo)簽添加ng-app屬性,可以指定一個(gè)應(yīng)用,表示此標(biāo)簽所包裹的內(nèi)容都屬于應(yīng)用(APP)。一般在HTML標(biāo)簽上添加。
<html lang="en" ng-app="App">
-
定義模塊
AngularJS提供了一個(gè)全局對(duì)象angular,在此全局對(duì)象下存在若干個(gè)方法,其中angular.module()方法用來(lái)定義一個(gè)模塊。
//第一個(gè)參數(shù)表示模塊的名稱(chēng),第二個(gè)參數(shù)表示此模塊依賴(lài)的其他模塊。
var App = angular.module('App', []);
-
定義控制器
控制器作為連接模型和視圖的橋梁而存在,所以當(dāng)我們定義好了控制器也就定義好了模型和視圖。
//App是一個(gè)模塊實(shí)例,通過(guò)模塊實(shí)例定義控制器。
//第一個(gè)參數(shù)表示控制器的名稱(chēng),第二個(gè)參數(shù)是一個(gè)數(shù)組。
//除了數(shù)組的最后一個(gè)元素是函數(shù)外,其余元素都是字符串,表明該控制器所依賴(lài)的服務(wù)。
App.controller('DemoContoller', ['$scope', function ($scope) {
//$scope模型對(duì)象
$scope.name = 'liangyiluo';
$scope.school = '華北理工大學(xué)';
$scope.courses = [
'MVC',
'指令',
'模塊化'
]
}]);
模型數(shù)據(jù)要展示到視圖上,所以需要將控制器關(guān)聯(lián)到視圖上,通過(guò)為HTML標(biāo)簽添加ng-controller屬性并賦值相應(yīng)的控制器的名稱(chēng),就確立了關(guān)聯(lián)關(guān)系。
<div ng-controller="DemoContoller">
<h1>{{name}}在{{school}}學(xué)習(xí)使用AngularJS</h1>
<ul>
<li ng-repeat="(key, course) in courses">第{{key+1}}天:{{course}}</li>
</ul>
</div>
以上就是AngularJS最基本的MVC工作模式。所以的AngularJS學(xué)習(xí)都會(huì)圍繞下圖展開(kāi)。

指令
HTML在構(gòu)建應(yīng)用(APP)時(shí)存在諸多不足,AngularJS通過(guò)擴(kuò)展一系列的HTML屬性或標(biāo)簽來(lái)彌補(bǔ)這些缺陷,所謂指令就是就是AngularJS自定義的一系列的HTML屬性或標(biāo)簽。這些指令都是以ng-作為前綴的。
- 內(nèi)置指令
ng-app:指定應(yīng)用根元素,至少有一個(gè)元素指定了此屬性。
ng-controller:指定控制器。
ng-show:控制元素是否顯示,true顯示,false不顯示。
ng-hide:控制元素是否隱藏,true隱藏,false不隱藏。
ng-if:控制標(biāo)簽是否存在,true存在,false不存在。
ng-src:圖片路徑。
ng-href:文件地址。
ng-class:控制類(lèi)名。{"class1":true,"class2":true}
ng-include:引入模版。js不能讀取文件,所以需要向服務(wù)器發(fā)送ajax請(qǐng)求模版。一般用于將多個(gè)頁(yè)面的共同的頭和尾抽離出來(lái)。
ng-disabled:表單禁用。
ng-readonlu:表單只讀。
ng-checked:?jiǎn)?復(fù)選框選中。
ng-selected:下拉框選中。
注:更多指令請(qǐng)參照官方文檔。 - 自定義指令
AngularJS允許根據(jù)實(shí)際業(yè)務(wù)需要自定義指令,通過(guò)angular全局對(duì)象下的directive方法實(shí)現(xiàn)。
App.directive('tag', function () {
return {
// E element
// A attribute
// C class
// M mark replace 必須為true
restrict: 'ECMA',
// template: '<ul><li>首頁(yè)</li><li>列表</li></ul>',
templateUrl: './list.html',
// replace: true
}
});
數(shù)據(jù)綁定
AngularJS是以數(shù)據(jù)作為驅(qū)動(dòng)的MVC框架,所有模型里的數(shù)據(jù)經(jīng)過(guò)控制器展示到視圖中。
所謂數(shù)據(jù)綁定就是將模型中的數(shù)據(jù)與對(duì)應(yīng)的視圖進(jìn)行關(guān)聯(lián),分為單向綁定和雙向綁定兩種方式。
- 單向綁定
<body ng-app="App">
<ul ng-controller="DemoController">
<li ng-bind="name"></li>
<li ng-cloak>{{name}}{{age}}</li>
<li ng-bind-template="{{name}}{{age}}"></li>
</ul>
<script src="./libs/angular.min.js"></script>
<script>
var App = angular.module('App', []);
App.controller('DemoController', ['$scope', function ($scope) {
//只能加模型中的數(shù)據(jù)放到視圖上。
$scope.name = 'itcast';
$scope.age = 10;
}]);
</script>
</body>
- 雙向綁定
雙向綁定可以實(shí)現(xiàn)模型數(shù)據(jù)和視圖模版的雙向傳遞。
在AngularJS中通過(guò){{}}或者ng-bind指令來(lái)實(shí)現(xiàn)模型數(shù)據(jù)向視圖模版的綁定,模型數(shù)據(jù)通過(guò)一個(gè)內(nèi)置服務(wù)$scope來(lái)提供,這個(gè)$scope是一個(gè)空對(duì)象,通過(guò)為這個(gè)對(duì)象添加屬性或者方法便可以在相應(yīng)的視圖模版里被訪問(wèn)。
注:{{}}在獲取數(shù)據(jù)時(shí)當(dāng)頁(yè)面刷新會(huì)有“閃爍”現(xiàn)象,給HTML標(biāo)簽添加ng-cloak可以解決(因?yàn)樵陧?yè)面加載時(shí)解析到{{}}時(shí),頁(yè)面無(wú)法解析,只有當(dāng)angular.js文件被加載后才可以解析,所以把a(bǔ)ngular.js文件提前也可以解決這個(gè)問(wèn)題)。通過(guò)ng-bind-template可以綁定多個(gè)數(shù)據(jù)。
通過(guò)為表單元素添加ng-model指令實(shí)現(xiàn)視圖模版向模型數(shù)據(jù)的綁定。
<body ng-app="App">
<div ng-controller="DemoController">
<!-- 要實(shí)現(xiàn)數(shù)據(jù)從視圖向模型傳遞需要借助于表單元素 -->
<input type="text" ng-model="msg">
<h4>{{msg}}</h4>
<button ng-click="show()">顯示</button>
</div>
<script src="./libs/angular.min.js"></script>
<script>
var App = angular.module('App', []);
App.controller('DemoController', ['$scope', function ($scope) {
$scope.show = function () {
alert($scope.msg);
}
}]);
</script>
</body>
- 事件綁定
AngularJS對(duì)事件也進(jìn)行了擴(kuò)展,通過(guò)在原有事件名稱(chēng)的基礎(chǔ)上添加ng-前綴,然后以屬性的形式添加到對(duì)應(yīng)的HTML標(biāo)簽上即可,如ng-click、ng-dbclick等。
<body>
<div ng-controller="DemoController">
<ul>
<li><button ng-click="single()">單擊</button></li>
</ul>
</div>
<script src="./libs/angular.min.js"></script>
<script>
var App = angular.module('App', []);
App.controller('DemoController', ['$scope', function ($scope) {
$scope.single = function () {
alert('我被單擊了');
}
}])
</script>
</body>
通過(guò)ng-repeat可以將數(shù)據(jù)遍歷到視圖中
<body ng-app="Demo">
<table>
<thead>
<tr>
<th>姓名</th>
<th>性別</th>
<th>年齡</th>
</tr>
</thead>
<tbody ng-controller="StarsController">
<tr ng-repeat="star in stars">
<td>{{star.name}}</td>
<td>{{star.sex}}</td>
<td>{{star.age}}</td>
</tr>
</tbody>
</table>
<script src="./libs/angular.min.js"></script>
<script>
var Demo = angular.module('Demo', []);
Demo.controller('StarsController', ['$scope', function ($scope) {
// 后面數(shù)據(jù)會(huì)來(lái)自于后端
$scope.stars = [
{name: '小紅', sex: '男', age: 62},
{name: '小強(qiáng)', sex: '男', age: 40},
{name: '小美', sex: '男', age: 39},
{name: '小明', sex: '女', age: 12}
];
}]);
</script>
</body>
通過(guò)ng-switch on可以對(duì)數(shù)據(jù)進(jìn)行篩選(類(lèi)似switch)
<body>
<div ng-controller="DemoController">
<ul>
<li ng-repeat="item in items" ng-switch="item">
<span ng-switch-when="css">{{item}}</span>
</li>
</ul>
</div>
<script src="./libs/angular.min.js"></script>
<script>
var App = angular.module('App', []);
App.controller('DemoController', ['$scope', function ($scope) {
$scope.items = ['html', 'css', 'js'];
}]);
</script>
</body>
- 不同控制器之間的數(shù)據(jù)傳遞
NG中多模塊開(kāi)發(fā)不是多個(gè)模塊再去使用多個(gè)ng-app,而是先確定主模塊,其他的子模塊添加到主模塊的中括號(hào)中,進(jìn)行注入。那么在主模塊中就可以使用子模塊了。
可以參照具體項(xiàng)目:https://github.com/zhongxiaolian/douban
那么繼續(xù)研究控制器之間的數(shù)據(jù)傳遞。
var app=angular.module('mainApp',[]);
app.controller('SelfCtrl', function($scope) {
$scope.click = function () {
//$broadcast廣播to-child事件的名稱(chēng),廣播的內(nèi)容是child
$scope.$broadcast('to-child', 'child');
//$emit事件發(fā)射器to-parent是事件的名稱(chēng) parent是傳的內(nèi)容
$scope.$emit('to-parent', 'parent');
}
});
app.controller('ParentCtrl', function($scope) {
$scope.$on('to-parent', function(event,data) {
console.log('ParentCtrl', data);
});
});
app.controller('ChildCtrl', function($scope){
$scope.$on('to-child', function(event,data) {
console.log('ChildCtrl', data);
});
});
作用域
通常AngularJS中應(yīng)用是由若干個(gè)視圖組合而成的,而視圖又都是HTML元素,并且HTML元素是可以相互嵌套的,另一方面視圖都隸屬于某個(gè)控制器,進(jìn)而控制器之間也必然會(huì)存在嵌套關(guān)系。每個(gè)控制器又對(duì)應(yīng)一個(gè)模型也就是$scope對(duì)象,不同層級(jí)控制器下的$scope便產(chǎn)生了作用域。
- 根作用域
一個(gè)AngularJS應(yīng)用在啟動(dòng)時(shí)會(huì)自動(dòng)創(chuàng)建一個(gè)根作用域$rootScope,這個(gè)根作用域在整個(gè)應(yīng)用范圍都是可以被訪問(wèn)到的。
//在根作用域初始化數(shù)據(jù)
<body ng-init="name='itcast';age=10">
</body>
- 子作用域
通過(guò)ng-controller指令可以創(chuàng)建一個(gè)子作用域,新建的作用域可以訪問(wèn)其父作用域中的數(shù)據(jù)。
過(guò)濾器
在AngularJS中使用過(guò)濾器格式化展示數(shù)據(jù),在{{}}中使用 “|”來(lái)調(diào)用過(guò)濾器,使用“:”傳遞參數(shù)。
- 內(nèi)置過(guò)濾器
1、currency;將數(shù)值格式轉(zhuǎn)換為貨幣格式
2、date:格式化日期
3、filter:在給定數(shù)組中選擇滿足條件的一個(gè)子集,并返回一個(gè)新數(shù)組,其條件可以是一個(gè)字符串、對(duì)象、函數(shù)。
4、json:將javascript對(duì)象轉(zhuǎn)換為JSON字符串。
5、limitTo:取出字符串或數(shù)組的前(正數(shù))幾位或者后(負(fù)數(shù))幾位。
6、lowercase:轉(zhuǎn)小寫(xiě)
7、uppercase:轉(zhuǎn)大寫(xiě)
8、number:數(shù)字格式化,可控制小數(shù)位數(shù)。
9、orderby:對(duì)數(shù)組進(jìn)行排序,第二個(gè)參數(shù)可控制方向。
<body ng-app="App">
<ul ng-controller="DemoController">
<!--加貨幣前綴-->
<li>{{price|currency:'¥'}}</li>
<!--日期格式化-->
<li>{{now|date:'yyyy/MM/dd hh:mm:ss'}}</li>
<!--遍歷數(shù)組過(guò)濾包含's'字符的元素-->
<li>{{items|filter:'s'}}</li>
<!--過(guò)濾包含age屬性,并且值為16的對(duì)象-->
<li>{{students|filter:{age: 16} }}</li>
<!--將js對(duì)象轉(zhuǎn)換為json-->
<li>{{students|json}}</li>
<!--從后向前取兩個(gè)-->
<li>{{items|limitTo:-2}}</li>
<!--所有字符轉(zhuǎn)大寫(xiě),并從前向后找3個(gè)-->
<li>{{str|uppercase|limitTo:3}}</li>
<!--轉(zhuǎn)小寫(xiě)-->
<li>{{str|lowercase}}</li>
<!--保留兩位小數(shù)-->
<li>{{num|number:2}}</li>
<!--第一個(gè)參數(shù)為要比較的屬性值,第二個(gè)參數(shù)true代表降序,false代表升序。-->
<li>{{items|orderBy: '':false}}</li>
<li>{{students|orderBy: 'age': true}}</li>
</ul>
<script src="./libs/angular.min.js"></script>
<script>
var App = angular.module('App', []);
App.controller('DemoController', ['$scope', function ($scope) {
$scope.price = 11.11;
$scope.now = new Date;
$scope.items = ['html', 'css', 'js'];
$scope.students = [
{name: '小紅', age: 16},
{name: '小明', age: 17},
{name: '小米', age: 10}
];
$scope.str = 'hello Angular';
$scope.num = '10.2345';
}]);
</script>
</body>
- 自定義過(guò)濾器
除了使用AngularJS內(nèi)置的過(guò)濾器外,還可以根據(jù)業(yè)務(wù)需要自定義過(guò)濾器,通過(guò)模塊實(shí)例對(duì)象的filter方法自定義過(guò)濾器。
var App = angular.module('App', []);
//這個(gè)過(guò)濾器要實(shí)現(xiàn)的功能是首字母大寫(xiě)
App.filter('capitalize', function () {
//過(guò)濾器實(shí)際上就是一個(gè)函數(shù),第一個(gè)參數(shù)表示要處理的數(shù)據(jù),第二個(gè)參數(shù)表示給過(guò)濾器傳遞的參數(shù)。
return function (input, arg2) {
return input[0].toUpperCase() + input.slice(1);
}
});
依賴(lài)注入
AngularJS采用模塊化的方式組織代碼,將一些邏輯封裝成一個(gè)對(duì)象或函數(shù),實(shí)現(xiàn)最大程度復(fù)用,這導(dǎo)致了使用者和被使用者之間存在依賴(lài)關(guān)系。
所謂依賴(lài)注入是指在運(yùn)行時(shí)自動(dòng)查找依賴(lài)關(guān)系,找到后傳遞給使用者的一種機(jī)制。
常見(jiàn)的AngularJS的內(nèi)置服務(wù)有$http、$location、$timeout、$rootScope等。
- 推斷式注入
沒(méi)有明確聲明依賴(lài),AngularJS會(huì)將函數(shù)參數(shù)名稱(chēng)當(dāng)成是依賴(lài)的名稱(chēng)。
var App = angular.module('App', []);
App.controller('DemoController', function ($scope, $http) {
});
注:這種方式存在一個(gè)問(wèn)題,當(dāng)代碼壓縮后函數(shù)的參數(shù)被壓縮,這樣便會(huì)造成依賴(lài)無(wú)法找到。
- 行內(nèi)注入
以數(shù)組形式明確聲明依賴(lài)關(guān)系,數(shù)組元素都是包含依賴(lài)名稱(chēng)的字符串,數(shù)組最后一個(gè)元素是依賴(lài)注入的目標(biāo)函數(shù)。
var App = angular.module('App', []);
// 行內(nèi)式注入,推薦使用這種依賴(lài)注入方式。
App.controller('DemoController', ['$scope', '$http', function ($scope, $http) {
$scope.name = '依賴(lài)注入';
}]);
服務(wù)
服務(wù)是一個(gè)對(duì)象或函數(shù),對(duì)外提供特定的功能。
- 內(nèi)置服務(wù)
1、$location是對(duì)原生Javascript的location對(duì)象的屬性和方法的封裝。
2、$timeout和$interval對(duì)原生Javascript的setTimeout和setInterval進(jìn)行了封裝。
var App = angular.module('App', []);
App.controller('DemoController', ['$scope', '$timeout', '$interval',function ($scope, $timeout, $interval) {
$timeout(function () {
$scope.msg = '執(zhí)行了';
}, 3000);
var timer = $interval(function () {
$scope.now = new Date;
}, 1000);
$scope.stop = function () {
$interval.cancel(timer);
}
}]);
- $filter在控制器中格式化數(shù)據(jù)
var App = angular.module('App', []);
App.controller('DemoController', ['$scope', '$filter', function ($scope, $filter) {
$scope.price = 11.11;
var currency = $filter('currency');
$scope.price = currency($scope.price,"¥");
$scope.str = 'hello angular';
var uppercase = $filter('uppercase');
$scope.str = uppercase($scope.str);
$scope.str1 = $filter('limitTo')($scope.str, 2);
}]);
- $log打印調(diào)試信息
var App = angular.module('App', []);
App.controller('DemoController', ['$log', function ($log) {
$log.info('普通信息');
$log.warn('警告信息');
$log.error('錯(cuò)誤信息');
$log.log('打印信息');
$log.debug('調(diào)試信息');
}]);
- $http用于向服務(wù)器發(fā)ajax請(qǐng)求
var App = angular.module('App', []);
App.controller('DemoController', ['$scope', '$http', '$log', function ($scope, $http, $log) {
$http({
url: 'example.php',
method: 'post',
headers: {
// 'Content-Type': 'application/x-www-form-urlencoded'
//上面這種請(qǐng)求頭會(huì)把請(qǐng)求數(shù)據(jù)設(shè)置成form-data形式
'Content-Type': 'application/json;charset=UTF-8'
//默認(rèn)的請(qǐng)求頭信息(Restful 發(fā)送的是JSON數(shù)據(jù))
},
// get 參數(shù)
params: {
name: 'itcast',
sex: '男'
}
// post參數(shù)
data: {
age: 10
}
}).success(function (info) {
$log.info(info);
});
}]);
// 接口方式
// SOAP(key=val&key=val,這種形式叫formData,Content-Type 設(shè)成 application/x-www-form-urlencoded,PHP后臺(tái)可以用$_POST來(lái)接收)
// RESTFUL(json數(shù)據(jù),這種形式叫Request Payload,Content-Type 設(shè)成 application/json;charset=UTF-8,也是默認(rèn)的,PHP后臺(tái)可以用file_get_contents("php://input") )
通過(guò)JSONP獲取天氣信息
var App = angular.module('App', []);
App.controller('WeatherController', ['$scope', '$http', function($scope, $http) {
$http({
method: 'jsonp', // 支持jsonp
//callback=JSON_CALLBACK是固定寫(xiě)法,服務(wù)器默認(rèn)獲取callback屬性值,JSON_CALLBACK是一個(gè)占位符,AngularJS底層會(huì)自動(dòng)生成一個(gè)函數(shù)替換它(被服務(wù)器調(diào)用,接收服務(wù)器返回的數(shù)據(jù))。
url: 'http://api.map.baidu.com/telematics/v3/weather?callback=JSON_CALLBACK',
params: {
location: '北京',
output: 'json',
ak: '0A5bc3c4fb543c8f9bc54b77bc155724'
}
})
.success(function (data) {
// 請(qǐng)求回的數(shù)據(jù)放到模型上
$scope.weatherData = data.results[0].weather_data;
});
}])
- 自定義服務(wù)
手動(dòng)將一些通用性的邏輯功能進(jìn)行封裝,方便以后使用。服務(wù)本質(zhì)上就是一個(gè)對(duì)象或函數(shù),所以自定義服務(wù)就是要返回一個(gè)對(duì)象或函數(shù)以供使用。
1、factory方法
var App = angular.module('App', []);
// 通過(guò)factory定義一個(gè)名叫showTime的服務(wù)
App.factory('showTime', ['$filter', function ($filter) {
var now = new Date();
var date = $filter('date');
return {
now: date(now, 'y-M-d H:m:s')
}
}]);
App.controller('DemoController', ['$scope', 'showTime', function($scope, showTime) {
$scope.now = showTime.now;
}])
2、service方法
var App = angular.module('App', []);
// 通過(guò)service方法自定義服務(wù)顯示日期
App.service('showTime', ['$filter', function($filter) {
var now = new Date();
var date = $filter('date');
//不需要return,直接賦值給this
this.now = date(now, 'y-M-d H:mm:ss');
}]);
App.controller('DemoController', ['$scope', 'showTime', function($scope, showTime) {
$scope.now = showTime.now;
}])
3、value方法
var App = angular.module('App', []);
// 自定義常量服務(wù)
App.value('author', 'itcast');
App.value('version', '1.0');
// 本質(zhì)上是一個(gè)服務(wù)
// 從表現(xiàn)形式上是一個(gè)常量
// 常量就是不變的值與變量相對(duì)應(yīng)
// 聲明依賴(lài)調(diào)用服務(wù)
App.controller('DemoController', ['$scope', 'author', 'version', function($scope, author, version) {
$scope.author = author;
$scope.ver = version;
}]);
模塊加載
AngularJS模塊可以在被加載和執(zhí)行之前對(duì)其自身進(jìn)行配置。

- 配置模塊
通過(guò)config方法實(shí)現(xiàn)對(duì)模塊的配置,AngularJS中的服務(wù)大部分都對(duì)應(yīng)一個(gè)provider,用來(lái)執(zhí)行與對(duì)應(yīng)服務(wù)相同的功能或?qū)ζ溥M(jìn)行配置。
比如$log,$http,$location都是內(nèi)置服務(wù),相對(duì)應(yīng)的provider分別是$logProvider,$httpProvider,$locationProvider。
下面以$log和$filter模塊為例進(jìn)行演示:
<body>
<div ng-controller="DemoController">
<h1>{{now}}</h1>
<h2>{{str|capitalize}}</h2>
</div>
<script src="./libs/angular.min.js"></script>
<script>
var App = angular.module('App', []);
// 配置$log服務(wù)(禁用debug)
// 允許一次配置多個(gè)服務(wù)(模塊), 傳遞的一個(gè)數(shù)組(依賴(lài)注入方式)
App.config(['$logProvider', '$filterProvider', function ($logProvider, $filterProvider) {
// 禁用debug功能
$logProvider.debugEnabled(false);
// 默認(rèn)9個(gè)過(guò)濾器,通過(guò)配置可以新增一些過(guò)濾器
$filterProvider.register('capitalize', function () {
// 新增一個(gè)過(guò)濾器
return function (input) {
return input[0].toUpperCase() + input.slice(1);
}
});
}]);
//視圖和模型綁定演示剛剛配置的過(guò)濾器
App.controller('DemoController', ['$scope', '$log', function ($scope, $log) {
// 測(cè)試配置后的結(jié)果
$log.debug('debug');
$scope.str = 'hello angular';
}]);
</script>
</body>
- 運(yùn)行模塊
服務(wù)是以模塊的形式存在的且對(duì)外提供特定的功能,之前都是將服務(wù)作為依賴(lài),注入到相應(yīng)的控制器,然后在控制器中進(jìn)行調(diào)用,除了這種方式我們還可以直接運(yùn)行服務(wù)模塊,AngularJS提供了run方法。
<body>
<div ng-controller="DemoController">
{{name}}
</div>
<script src="./libs/angular.min.js"></script>
<script>
var App = angular.module('App', []);
// 直接運(yùn)行$http、$rootScope服務(wù),沒(méi)有作為依賴(lài)項(xiàng)傳遞給其他模塊。
// $rootScope是根作域
App.run(['$http', '$rootScope', function ($http, $rootScope) {
// 直接調(diào)用$http
$http({
url: 'example.php',
method: 'get'
});
// 在根作用域賦值。
$rootScope.name = '祖宗';
}]);
App.controller('DemoController', ['$scope', function($scope) {
$scope.name = '后代';
}])
</script>
</body>
不但如此,run方法還是最先被執(zhí)行的,利用這個(gè)功能我們可以將一些需要優(yōu)先執(zhí)行的功能通過(guò)run方法來(lái)運(yùn)行,比如驗(yàn)證用戶是否登錄,未登錄則不允許進(jìn)行任何操作。
路由
- 單頁(yè)面應(yīng)用的介紹
一個(gè)應(yīng)用是由多個(gè)視圖組成的,需要根據(jù)不同的業(yè)務(wù)邏輯展示給用戶不同的視圖,路由則是實(shí)現(xiàn)這一功能的關(guān)鍵,但頁(yè)面應(yīng)用可以提升性能,增強(qiáng)用戶體驗(yàn)。
SPA(Single Page Application):指的是通過(guò)單頁(yè)面展示所有功能,通過(guò)Ajax動(dòng)態(tài)獲取數(shù)據(jù)然后實(shí)時(shí)進(jìn)行渲染,結(jié)合CSS3動(dòng)畫(huà)模仿原生APP交互,然后在進(jìn)行打包(使用工具把Web應(yīng)用包一個(gè)殼,這個(gè)殼本質(zhì)上就是一個(gè)瀏覽器)變成一個(gè)“原生應(yīng)用”。
在PC端也有廣泛的應(yīng)用,通常情況下使用Ajax異步請(qǐng)求數(shù)據(jù),然后實(shí)現(xiàn)內(nèi)容的局部刷新,局部刷新的本質(zhì)就是動(dòng)態(tài)生成DOM,新生成的DOM元素并沒(méi)有真實(shí)存在于文檔中,所以當(dāng)再次刷新時(shí)新添加的DOM元素會(huì)“丟失”,通過(guò)單頁(yè)面應(yīng)用可以很好的解決這個(gè)問(wèn)題。
路由。 - 路由的使用
在后端開(kāi)發(fā)過(guò)程中通過(guò)URL地址可以實(shí)現(xiàn)頁(yè)面(視圖)的切換,但是AngularJS是一個(gè)純前端的MVC框架,在開(kāi)發(fā)但頁(yè)面應(yīng)用時(shí),所有功能都在同一頁(yè)面完成,所以無(wú)需切換URL地址(即不允許產(chǎn)生跳轉(zhuǎn)),但WEB應(yīng)用中又經(jīng)常通過(guò)鏈接(a標(biāo)簽)來(lái)更新頁(yè)面(視圖),當(dāng)點(diǎn)擊鏈接時(shí)還要阻止其向服務(wù)器發(fā)起請(qǐng)求,通過(guò)錨點(diǎn)(頁(yè)內(nèi)跳轉(zhuǎn))可以實(shí)現(xiàn)這一點(diǎn)。
實(shí)現(xiàn)單頁(yè)面應(yīng)用需要具備:
1、只有一個(gè)頁(yè)面。
2、鏈接使用錨點(diǎn)。
3、服務(wù)器。
下面是一個(gè)簡(jiǎn)單的使用NG路由的例子:
<body>
<div class="wrapper">
<!-- 導(dǎo)航菜單 -->
<ul>
<li>
<a href="#/contact/5/abc/7">Contact Us</a>
</li>
<li>
<a href="#/list">List</a>
</li>
</ul>
<div class="content">
<!-- 占位符 -->
<div ng-view></div>
</div>
</div>
<!-- AngularJS核心框架 -->
<script src="./libs/angular.min.js"></script>
<!-- 路由模塊理解成NG插件 -->
<script src="./libs/angular-route.js"></script>
<script>
// 依賴(lài)ngRoute模塊
var App = angular.module('App', ['ngRoute']);
// 需要對(duì)路由模塊進(jìn)行配置,使其正常工作
App.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/contact/:id/:page/:p', {
templateUrl: './contact.html',
controller: 'ContactController' // 定義控制器
})
.when('/list', {
templateUrl: './list.html', // 視圖模板
controller: 'ListController' // 定義控制器
})
.otherwise({
redirectTo: '/contact'
});
}]);
App.controller('ListController', ['$scope', '$http', function ($scope, $http) {
$http({
url: '10-02.php',
}).success(function (info) {
$scope.items = info;
});
}]);
App.controller('ContactController', ['$scope', '$http','$routeParams', function ($scope, $http,$routeParams) {
console.log($routeParams);
$http({
url: 'contact.php'
}).success(function (info) {
$scope.content = info;
});
}]);
</script>
</body>
單頁(yè)面應(yīng)用原理:
<body>
<div class="wrapper">
<!-- 導(dǎo)航菜單 -->
<ul>
<li class="active">
<a href="#index">Index</a>
</li>
<li>
<a href="#introduce">Introduce</a>
</li>
<li>
<a href="#contact">Contact Us</a>
</li>
</ul>
<!-- 內(nèi)容 -->
<div class="content">
Index Page
</div>
</div>
<script>
//和tab欄不同:
//1、a標(biāo)簽不需要添加click事件
//2、重復(fù)點(diǎn)擊不會(huì)多次觸發(fā)事件,因?yàn)閔ash并沒(méi)變。
// 監(jiān)聽(tīng)錨點(diǎn)變化然后發(fā)送請(qǐng)求
// hashchange事件可以監(jiān)聽(tīng)錨點(diǎn)變化
window.addEventListener('hashchange', function () {
// 獲取錨點(diǎn)
var hash = location.hash;
// 處理#
hash = hash.slice(1);
var xhr = new XMLHttpRequest;
// 將錨點(diǎn)做為參數(shù)傳遞給服務(wù)端進(jìn)處理
xhr.open('get', '10-01.php?hash=' + hash);
xhr.send(null);
xhr.onreadystatechange = function () {
if(xhr.readyState == 4 && xhr.status == 200) {
var result = xhr.responseText;
// 將返回結(jié)果添加到頁(yè)面
document.querySelector('.content').innerHTML = result;
}
}
});
</script>
</body>
通過(guò)上面的例子發(fā)現(xiàn)可以通過(guò)監(jiān)聽(tīng)hashchange事件監(jiān)聽(tīng)到錨點(diǎn)的變化,進(jìn)而可以實(shí)現(xiàn)為不同的錨點(diǎn)綁定不同的視圖,單頁(yè)面應(yīng)用就是基于這個(gè)原理實(shí)現(xiàn)的。
注:在1.2版本之前路由器的功能是包含在AngularJS核心代碼中的,之后的版本將路由器獨(dú)立成一個(gè)模塊,下載angular-route.js。
- 路由參數(shù)
1、$routeProvider提供兩個(gè)方法匹配路由,分別是when和otherwise,when需要兩個(gè)參數(shù),othersize方法作為when方法的補(bǔ)充只需要一個(gè)參數(shù),其中when方法可以被多次調(diào)用。
2、第一個(gè)參數(shù)是一個(gè)字符串,代表當(dāng)前URL的hash值。
3、第二個(gè)參數(shù)是一個(gè)對(duì)象,用于配置當(dāng)前路由的視圖、控制器等。
template:字符串形式的模版。
templateURL:引入外部視圖模版。
controller:視圖模版所屬的控制器。
redirectTo:跳轉(zhuǎn)到其他路由。
4、獲取路由傳遞的參數(shù),在控制器中注入$routeParams可以獲取路由傳遞的參數(shù)。
內(nèi)置jQuery
在沒(méi)有引入jQuery之前,NG實(shí)現(xiàn)了簡(jiǎn)版的jQuery Lite,通過(guò)angular.element不能選擇元素,但是可以將一個(gè)DOM元素轉(zhuǎn)換成jQuery對(duì)象,如果提前引入了jQuery則angular.element則完全等于jQuery。