目錄
2. 前言
Angularjs開發CRUD類型的Web系統生產力驚人,與jQuery,YUI,kissy,Extjs等前端框架區別非常大,初學者在學習的過程中容易以自己以往的經驗來學習Angularjs 往往走入誤區,最典型的特征是在的開發過程中,使用大量的 指令(directive) 來實現許多操作DOM的功能,從而失去了angularjs快速開發的特性,最后不得不放棄使用。此系列的文章並不會像其他介紹Angularjs技術文檔一樣將每個技術細節統統照顧到,而是通過實戰項目先讓初學者有個大概的了解,然后大家在由淺入深逐漸熟悉每一個細節。
Github Angularjs
寫此博客的時候angularjs官方穩定版已經更新到 “1.4.2”,內部測試版更新到“2.0.0-alpha.30”
本篇博客使用angularjs 1.4.2 版本
angularjs 1.4.2下載地址
首先放一個招牌Demo:
<!--設置angularjs在頁面上的訪問域-->
<html ng-app="Yiim">
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<script src="http://files.cnblogs.com/files/Arrays/angular.min.js"></script>
<script type="text/javascript">
//聲明一個私有函數域
(function () {
//創建一個app模塊(你就想象成C#里面的一個類庫吧)
var app = angular.module("Yiim", []);
//在app模塊中創建一個"tmplController"控制器
app.controller("tmplController", ["$scope", function ($scope) {
//設置(val)變量值
$scope.val = "Google是最棒的搜索引擎。";
}]);
})()
</script>
</head>
<body>
<!--設置當前div的控制器為"tmplController"-->
<div ng-controller="tmplController">
<div>{{val}}</div>
</div>
</body>
</html>
3.Angularjs名詞與概念
2.1 單頁Web應用(SinglePage):
顧名思義,只使用一個頁面的Web應用程序.單頁面應用是指用戶通過瀏覽器加載獨立的HTML頁面,Ajax加載數據頁面無刷新,實現操作各種操作。
2.2 模板(template):
這里的模板是指前端模板,在angularjs 之外已經有非常豐富的JavaScript模板引擎了,例如artTemplate,Mustache,doT.js等。
Angularjs 內置有自己的模板引擎。
通過下面的DEMO我們一起了解一下Angularjs 內置模板引擎:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>angularjs 模板解釋</title>
<script src="http://files.cnblogs.com/files/Arrays/angular.min.js"></script>
<script type="text/javascript">
//聲明一個私有函數域
(function () {
var app = angular.module("Yiim", []); //創建模塊
app.controller("tmplController", ["$scope", function ($scope) {
//給變量val賦值
$scope.val = "Google是最好的搜索引擎";
//給變量list賦值
$scope.list = [
{ title: "博客園", url: "http://www.cnblogs.com" },
{ title: "知乎", url: "http://www.zhihu.com" },
{ title: "codeproject", url: "http://www.codeproject.com/" },
{ title: "google", url: "http://www.google.com/" }
]
//給變量hasValue賦值
$scope.hasValue = false;
}]);
})()
</script>
</head>
<body ng-app="Yiim">
<div ng-controller="tmplController">
<!--普通輸出-->
<div>{{val}}</div>
<!--循環-->
<ul ng-repeat="item in list">
<li><a href="{{item.url}}" rel=nofollow>{{item.title}}</a></li>
</ul>
<!--條件語句-->
<div ng-if="!hasValue">
Angularjs條件語句
</div>
</div>
</body>
</html>
以上代碼首先創建一個"Yiim"模塊,然后在模塊中添加了一個名詞為"tmplController"的控制器,然后給scope添加三個屬性“val”,“list”,“hasValue”,並賦值。
在模板頁面設置angularjs作用域為"body"標簽內,名詞為"Yiim"
<body ng-app="Yiim">
在作用域中設置控制器為"tmplController"
<div ng-controller="tmplController">
例子中提供了3種輸出方式(普通輸出,循環,條件語句),當然angularjs不僅僅這幾種方式
“ng-repeat”,“ng-if” 這都是通過指令實現。我們在下一節(2.5 )將詳細講解
2.3 控制器(controller):
控制器可以理解為控制頁面某個區塊的方法。其中有一個非常重要的對象 $scope是這個控制器與頁面控制器區域溝通的橋梁。angularjs最精華的部分是雙向綁定,失去了雙向綁定angularjs就失去了自己的靈魂。這也是和其他以DOM操作的框架比最大的區別。放DEMO
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>angularjs控制器介紹</title>
<script src="http://files.cnblogs.com/files/Arrays/angular.min.js"></script>
<script type="text/javascript">
(function () {
var app = angular.module("Yiim", []);
app.controller("cntoController", ["$scope", function ($scope) {
var defaults = "知乎 - 與世界分享你的知識、經驗和見解";
//設置值
$scope.val = defaults;
$scope.click = function () {
$scope.val = defaults;
};
}]);
})()
</script>
</head>
<body ng-app="Yiim">
<div ng-controller="cntoController">
<!--綁定值-->
<div><textarea ng-model="val"></textarea></div>
<!--輸出值-->
<div>{{val}}</div>
<!--綁定方法-->
<div><button ng-click="click()">重置</button></div>
</div>
</body>
</html>
控制器演示效果 點擊此運行
與2.2節例子相同是,我們首先創建了一個模塊,然后在模塊中添加一個控制器方法 "cntoController".
在控制器里我們給scope添加了一個屬性"val" 和一個方法 "click"。
在頁面中我們使用"ng-model"指令綁定控制器中設置的"val"
<div><textarea ng-model="val"></textarea></div>
緊接着我們把綁定的值輸出處理
<div>{{val}}</div>
通過內置的綁定方法click 我們重置字符串
$scope.click = function () {
$scope.val = defaults;
};
2.4 路由(route):
單頁Web應用由於沒有后端URL資源定位的支持,需要自己實現URL資源定位。angularjs使用瀏覽器URL "#" 后的字符串來定位資源,區分不同的功能模塊。
路由並非在angularjs核心文件內,你需要另外加入一段腳本 “angular-route.min.js”
需要注意的是在創建 “app” 對象是需要填寫對 ngRoute 依賴
var app = angular.module("Yiim", ['ngRoute']);//注意 ngRoute
下面我們同樣的展示一個demo
主頁面 route.html
<!DOCTYPE html>
<html ng-app="Yiim" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>angularjs路由介紹</title>
<script src="http://files.cnblogs.com/files/Arrays/angular.min.js"></script>
<script src="http://files.cnblogs.com/files/Arrays/angular-route.min.js"></script>
<script type="text/javascript">
//聲明一個私有函數域
(function () {
//設置當前模塊依賴,“ngRoute”,用.NET的理解就是給這個類庫添加“ngRoute”引用
var app = angular.module("Yiim", ['ngRoute']);
//配置路由
app.config(['$routeProvider', function ($routeProvider) {
var route = $routeProvider;
//指定URL為“/” 控制器:“indexController”,模板:“route.html”
route.when('/list', { controller: 'listController', templateUrl: 'route-list.html' });
//注意“/view/:id” 中的 “:id” 用於捕獲參數ID
route.when('/view/:id', { controller: 'viewController', templateUrl: 'route-view.html' });
//跳轉
route.otherwise({ redirectTo: '/list' });
}]);
//創建一個提供數據的服務器
app.factory("service", function () {
var list = [
{ id: 1, title: "博客園", url: "http://www.cnblogs.com" },
{ id: 2, title: "知乎", url: "http://www.zhihu.com" },
{ id: 3, title: "codeproject", url: "http://www.codeproject.com/" },
{ id: 4, title: "google", url: "http://www.google.com/" }
];
return function (id) {
//假如ID為無效值返回所有
if (!id) return list;
var t = 0;
//匹配返回的項目
angular.forEach(list, function (v, i) {
if (v.id == id) t = i;
});
return list[t];
}
})
//創建控制器 indexController
app.controller("listController", ["$scope", "service", function ($scope, service) {
//獲取所有數據
$scope.list = service();
}]);
//創建查看控制器 viewController, 注意應為需要獲取URL ID參數 我們多設置了一個 依賴注入參數 “$routeParams” 通過它獲取傳入的 ID參數
app.controller("viewController", ["$scope", "service", '$routeParams', function ($scope, service, $routeParams) {
$scope.model = service($routeParams.id || 0) || {};
}])
})()
</script>
</head>
<body>
<div><a href="#/list">列表</a></div>
<div ng-view>
</div>
</body>
</html>
列表頁面 route-list.html
<ul ng-repeat="item in list">
<li><a href="#view/{{item.id}}">{{item.title}}</a></li>
</ul>
詳細頁面 route-view.html
<div>
<div>網站ID:{{model.id}}</div>
<div>網站名稱:<a href="{{model.url}}" rel="nofollow">{{model.title}}</a></div>
<div>訪問地址:{{model.url}}</div>
</div>
演示效果:點擊此運行
以上代碼中,我們首先配置了三條個處理個局部頁面的路由
路由處理列表頁並設置控制器為"listController",指定模板頁為"route-list.html"
route.when('/list', { controller: 'listController', templateUrl: 'route-list.html' });
與上面不同的是第二條路由中包含":id"用於捕獲URL后面的參數 。
route.when('/view/:id', { controller: 'viewController', templateUrl: 'route-view.html' });
處理所有未匹配到的路由跳轉到 "'/list'"內。
route.otherwise({ redirectTo: '/list' });
我們還使用了模塊方法 "factory" 創建一個"service" 服務,用於獲取數據列表
后面我們聲明了兩個控制器"listController","viewController",同時配置對"service"的依賴,"viewController" 中我們還添加對 "$routeParams" 的依賴,用於獲取路由捕獲的id。
需要注意的是我們再主頁面聲明了"ng-view"用於指定局部頁面和控制器作用范圍。
<div ng-view></div>
2.5 指令(directive):
指令(directive)並不是什么高深的東西,我們簡單理解為通過聲明 特殊的標簽,屬性..等來處理瀏覽器無法渲染的功能。通過JavaScript將指令替換成瀏覽器可以識別的標簽。
當前這不是它存在的唯一意義。在上面的例子中我們已經見到了“ng-if”,"ng-repeat"等這些angularjs 內置的指令。當然我們也可以定義自己使用的指令。
- 通過指令可以實現對DOM操作
- 可以跟加簡潔的實現某些功能
- 通過指令可以集成其他插件 例如jQuery插件
<!DOCTYPE html>
<html ng-app="Yiim" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>angularjs指令演示</title>
<script src="//cdn.bootcss.com/jquery/2.1.4/jquery.js"></script>
<script src="http://files.cnblogs.com/files/Arrays/angular.min.js"></script>
<script type="text/javascript">
//聲明一個私有函數域
(function () {
var app = angular.module("Yiim", []);
//創建一個提供數據的服務器
app.factory("service", function () {
var list = [
{ id: 1, title: "博客園", url: "http://www.cnblogs.com" },
{ id: 2, title: "知乎", url: "http://www.zhihu.com" },
{ id: 3, title: "codeproject", url: "http://www.codeproject.com/" },
{ id: 4, title: "google", url: "http://www.google.com/" }
];
return function (id) {
//假如ID為無效值返回所有
if (!id) return list;
var t = 0;
//匹配返回的項目
angular.forEach(list, function (v, i) {
if (v.id == id) t = i;
});
return list[t];
}
})
//創建指令imCheck 在HTML中的語法為 im-check
app.directive("imCheck", [function () {
return {
restrict: 'A',
replace: false,
link: function (scope, element) {
var all = "thead input[type='checkbox']";
var item = "tbody input[type='checkbox']";
//當點擊選擇所有事便利所有項目
element.on("change", all, function () {
var o = $(this).prop("checked");
var tds = element.find(item);
tds.each(function (i, check) {
$(check).prop("checked", o);
});
});
//子項修改時的超值
element.on("change", item, function () {
var o = $(this).prop("checked");
var isChecked = true;
if (o) {
element.find(item).each(function () {
if (!$(this).prop("checked")) {
isChecked = false;
return false;
}
return true;
});
}
element.find(all).prop("checked", o && isChecked);
});
}
};
}])
app.controller("dectController", ['$scope', 'service', function ($scope, service) {
$scope.list = service();
}])
})();
</script>
</head>
<body>
<!--注意一下標簽 im-check 指定使用的指令-->
<table ng-controller="dectController" im-check>
<thead>
<tr>
<th><input type="checkbox">選擇</th>
<th>網站ID</th>
<th>網站名稱</th>
<th>鏈接地址</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in list">
<td><input type="checkbox"></td>
<td>{{item.id}}</td>
<td>{{item.title}}</td>
<td>{{item.url}}</td>
</tr>
</tbody>
</table>
</body>
</html>
演示效果 點擊此運行
上面的例子中,我們使用模塊創建了一個指令"imCheck",並在指令方法"link"注冊了使用當前指令的dom對象注冊了兩個delegate方法 處理全選和子選擇項狀態改變處理的方法。
"imCheck" 對應在html頁面的屬性為 "im-check" 注意大小寫。
<table ng-controller="dectController" im-check>
還要注意的是我們使用了jQuery來操作dom節點。
2.6 前端模塊化開發:
模塊化開發不是什么新鮮的概念,后端開發過程中包,類庫這些把功能相近的東西放在一起。前端開發很長一段時間混亂無比,腳本之間的沖突,依賴,變量函數覆蓋各種奇奇怪怪的問題。模塊化開發在前端的定義:將功能相近的組件封裝到一塊,通過前端依賴注入解決依賴順序和變量作用域的問題. 代表框架有Seajs,Requirejs。
使用模塊化編程實現angularjs多種模塊,解決依賴問題
<!DOCTYPE html>
<html ng-app="Yiim" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>angularjs 模塊化開發</title>
<script src="http://files.cnblogs.com/files/Arrays/angular.min.js"></script>
<script type="text/javascript">
//聲明一個私有函數域
(function () {
//創建一個Yiim.service 模塊
var service = angular.module("Yiim.service", []);
//創建一個Yiim.controller 模塊
var controller = angular.module("Yiim.controller", []);
//指令模塊
var directive = angular.module("Yiim.directive", []);
//過濾器模塊
var filter = angular.module("Yiim.filter", []);
//Yiim.service添加一個服務
service.factory("service", [function () {
return { key: "Service" };
}]);
//Yiim.controller添加一個控制器
controller.controller("indexController", ['$scope', 'service', function ($scope, service) {
$scope.service = service;
}]);
//獲取依賴
var app = angular.module("Yiim", ['Yiim.service', 'Yiim.controller', 'Yiim.directive', 'Yiim.filter']);
})();
</script>
</head>
<body>
<div ng-controller="indexController">{{service.key}}</div>
</body>
</html>
2.7 過濾器(filter):
angularjs過濾器,用來格式化數據(轉化,排序,篩選等操作)。
<!DOCTYPE html>
<html ng-app="Yiim" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>angularjs 過濾器</title>
<script src="http://files.cnblogs.com/files/Arrays/angular.min.js"></script>
<script type="text/javascript">
//聲明一個私有函數域
(function () {
var app = angular.module("Yiim", []);
app.controller("namesController", ["$scope", function ($scope) {
$scope.names = [
{ "Name": "Alfreds Futterkiste", "City": "Berlin", "Country": "Germany" },
{ "Name": "Berglunds snabbköp", "City": "Luleå", "Country": "Sweden" },
{ "Name": "Centro comercial Moctezuma", "City": "México D.F.", "Country": "Mexico" },
{ "Name": "Ernst Handel", "City": "Graz", "Country": "Austria" },
{ "Name": "FISSA Fabrica Inter. Salchichas S.A.", "City": "Madrid", "Country": "Spain" },
{ "Name": "Galería del gastrónomo", "City": "Barcelona", "Country": "Spain" },
{ "Name": "Island Trading", "City": "Cowes", "Country": "UK" },
{ "Name": "Königlich Essen", "City": "Brandenburg", "Country": "Germany" },
{ "Name": "Laughing Bacchus Wine Cellars", "City": "Vancouver", "Country": "Canada" },
{ "Name": "Magazzini Alimentari Riuniti", "City": "Bergamo", "Country": "Italy" },
{ "Name": "North/South", "City": "London", "Country": "UK" },
{ "Name": "Paris spécialités", "City": "Paris", "Country": "France" },
{ "Name": "Rattlesnake Canyon Grocery", "City": "Albuquerque", "Country": "USA" },
{ "Name": "Simons bistro", "City": "København", "Country": "Denmark" },
{ "Name": "The Big Cheese", "City": "Portland", "Country": "USA" },
{ "Name": "Vaffeljernet", "City": "Århus", "Country": "Denmark" },
{ "Name": "Wolski Zajazd", "City": "Warszawa", "Country": "Poland" }
];
}])
})()
</script>
</head>
<body>
<div ng-controller="namesController">
<p>輸入過濾:</p>
<p><input type="text" ng-model="name"></p>
<ul>
<li ng-repeat="x in names | filter:name | orderBy:'Country'">
{{ (x.Name | uppercase) + ', ' + x.country }}
</li>
</ul>
</div>
</body>
</html>
演示效果 點擊此運行
我們使用angularjs內置的過濾器 "filter","orderBy"。
x in names | filter:name | orderBy:'Country'
含義為將集合 "names" 傳入過濾器 "filter"匹配字符串為"name"的項目,然后將匹配后的集合傳入 "orderBy"過濾器,以"Country"屬性進行排序。
在輸出變量時我們使用"uppercase"過濾器轉化大小寫
x.Name | uppercase