理解AngularJs篇:30分鐘快速掌握AngularJs
一、前言
對(duì)于前端系列,自然少不了AngularJs的介紹了。在前面文章中,我們介紹了如何使用KnockoutJs來(lái)打造一個(gè)單頁(yè)面程序,后面一篇文章將介紹如何使用AngularJs的開發(fā)一個(gè)單頁(yè)面應(yīng)用程序。在開始使用AngularJs開發(fā)SPA之前,我覺得有必要詳細(xì)介紹下AngularJs所涉及的知識(shí)點(diǎn)。所有也就有了這篇文章。
二、AngularJs介紹
AngularJS是Google推出的一款Web應(yīng)用開發(fā)框架。它提供了一系列兼容性良好并可擴(kuò)展的服務(wù),包括數(shù)據(jù)綁定、DOM操作、MVC和依賴注入等特性。相信下面圖片可以更好地詮釋AngularJs具體支持哪些特性。
從上圖可以發(fā)現(xiàn),AngularJs幾乎支持構(gòu)建一個(gè)Web應(yīng)用的所有內(nèi)容——數(shù)據(jù)綁定、表單驗(yàn)證、路由、依賴注入、控制器、模板和視圖等。
但并不是所有的應(yīng)用都適合用AngularJs來(lái)做。AngularJS主要考慮的是構(gòu)建CURD應(yīng)用,但至少90%的Web應(yīng)用都是CURD應(yīng)用。哪什么不適合用AngularJs來(lái)做呢? 如游戲、圖像界面編輯器等應(yīng)用不適合用AngularJs來(lái)構(gòu)建。
三、AngularJS核心知識(shí)點(diǎn)
接下來(lái),我們就詳細(xì)介紹了AngularJS的幾個(gè)核心知識(shí)點(diǎn),其中包括:
- 指令(directive)和 數(shù)據(jù)綁定(Data Binding)
- 模板(Module)
- 控制器(Controller)
- 路由(Route)
- 服務(wù)(service)
- 過濾器(Filter)
3.1 指令和數(shù)據(jù)綁定
在沒有使用AngularJs的Web應(yīng)用,要實(shí)現(xiàn)前臺(tái)頁(yè)面邏輯通過給HTML元素設(shè)置ID,然后使用Js或Jquery通過ID來(lái)獲取HTML DOM元素。而AngularJS不再需要給HTML元素設(shè)置ID,而是使用指令的方式來(lái)指導(dǎo)HTML元素的行為。這樣做的好處是開發(fā)人員看到HTML元素以及指令(Directive)就可以理解其行為,而傳統(tǒng)設(shè)置Id的方式并不能給你帶來(lái)任何有用的信息,你需要深入去查看對(duì)應(yīng)的Js代碼來(lái)理解其行為。
上面介紹了這么多,好像沒有正式介紹指令是什么呢?光顧著介紹指令的好處和傳統(tǒng)方式的不同了。指令可以理解為聲明特殊的標(biāo)簽或?qū)傩浴ngularJs內(nèi)置了很多的指令,你所看到的所有以ng開頭的所有標(biāo)簽,如ng-app、ng-init、ng-if、ng-model等。
- ng-app:用于標(biāo)識(shí)頁(yè)面是一個(gè)AngularJs頁(yè)面。一般加載HTML的根對(duì)象上。
- ng-init 用于初始化了一個(gè)變量
- ng-model:用戶在Property和Html控件之間建立雙向的數(shù)據(jù)綁定(Data Binding)。這樣Html控件的值改變會(huì)反應(yīng)到Property上,反過來(lái)也同樣成立。
AngularJs通過表達(dá)式的方式將數(shù)據(jù)綁定到HTML標(biāo)簽內(nèi)。AngularJs的表達(dá)式寫在雙大括號(hào)內(nèi):{{expression}}
下面具體看一個(gè)指令的例子:
<!DOCTYPE html> <html ng-app xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Using Directives and Data Binding Syntax</title> </head> <body ng-init="name = '歡迎學(xué)習(xí)AngularJS'"> <div> Name: <input type="text" ng-model="name" /> {{name}} </div> <script src="/Scripts/angular.min.js"></script> </body> </html>
當(dāng)我們改變輸入框的值時(shí),對(duì)應(yīng)的改變會(huì)反應(yīng)到name屬性上,從而反應(yīng)到表達(dá)式的值。AngularJs中雙向綁定的使用主要是靠ng-model指令來(lái)完成的。前面說的都是一些AngularJs內(nèi)置的指令,其實(shí)我們也可以自定義指令。關(guān)于這部分內(nèi)容將會(huì)在后面介紹到。
3.2 模板
在Asp.net MVC中提供了兩種頁(yè)面渲染模板,一種是Aspx,另一種是Razor.然而Asp.net MVC的這兩種模板都是后端模板,即頁(yè)面的渲染都是在服務(wù)端來(lái)完成的。這樣不可避免會(huì)加重服務(wù)器端的壓力。AngularJs的模板指的是前端模板。AngularJS有內(nèi)置的前端模板引擎,即所有頁(yè)面渲染的操作都是放在瀏覽器端來(lái)渲染的,這也是SPA程序的一個(gè)優(yōu)勢(shì)所在,所有前端框架都內(nèi)置了前端模板引擎,將頁(yè)面的渲染放在前端來(lái)做,從而減輕服務(wù)端的壓力。
在AngularJs中的模板就是指帶有ng-app指令的HTML代碼。AngularJs發(fā)現(xiàn)Html頁(yè)面是否需要用AngularJs模板引擎去渲染的標(biāo)志就是ng-app標(biāo)簽。
在AngularJs中,我們寫的其實(shí)也并不是純的Html頁(yè)面,而是模板,最終用戶看到的Html頁(yè)面(也就是視圖)是通過模板渲染后的結(jié)果。
下面來(lái)看下模板的例子:
<!DOCTYPE html> <html ng-app="mainApp"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Template Demo</title> <script src="http://sandbox.runjs.cn/uploads/rs/376/pbcx3e1z/angular.min.js"></script> <script> (function() { // 創(chuàng)建模塊 var mainApp = angular.module("mainApp",[]); // 創(chuàng)建控制器,并注入scope mainApp.controller("tempController", ["$scope", function ($scope) { $scope.val = "Welcome to Study AngularJs."; }]); })() </script> </head> <body> <h2>AngularJS 模塊演示</h2> <div ng-controller="tempController"> <div><input type="text" ng-model="val"> {{val}}</div> </div> </body> </html>
3.3 控制器
其實(shí)模板中的例子中,我們就已經(jīng)定義了名為"tempController"的控制器了。接下來(lái),我們?cè)僭敿?xì)介紹下AngularJs中的控制器。其實(shí)AngularJs中控制器的作用與Asp.net MVC中控制器的作用是一樣的,都是模型和視圖之間的橋梁。而AngularJs的模型對(duì)象就是$scope。所以AngularJs控制器知識(shí)$scope和視圖之間的橋梁,它通過操作$scope對(duì)象來(lái)改變視圖。下面代碼演示了控制器的使用:
<!DOCTYPE html> <html ng-app="mainApp"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>AngularJS 控制器演示</title> <script src="http://sandbox.runjs.cn/uploads/rs/376/pbcx3e1z/angular.min.js"> </script> <script> (function() { // 創(chuàng)建模塊 var mainApp = angular.module("mainApp", []); mainApp.controller("cntoController", ["$scope", function ($scope) { var defaultValue = "Learninghard 前端系列"; $scope.val = defaultValue; $scope.click = function () { $scope.val = defaultValue; }; }]); })() </script> </head> <body> <h2>AngularJS 控制器演示</h2> <div ng-controller="cntoController"> <div><textarea ng-model="val"></textarea></div> <div>{{val}}</div> <div><button ng-click="click()">重置</button></div> </div> </body> </html>
3.4 路由
之所以說AngularJs框架=MVC+MVVM,是因?yàn)锳ngularJs除了支持雙向綁定外(即MVVM特點(diǎn)),還支持路由。在之前介紹的KnockoutJs實(shí)現(xiàn)的SPA中,其中路由借用了Asp.net MVC中路由機(jī)制。有了AngularJs之后,我們Web前端頁(yè)面完全可以不用Asp.net MVC來(lái)做了,完全可以使用AngularJs框架來(lái)做。
單頁(yè)Web應(yīng)用由于沒有后端URL資源定位的支持,需要自己實(shí)現(xiàn)URL資源定位。AngularJs使用瀏覽器URL"#"后的字符串來(lái)定位資源。路由機(jī)制并非在AngularJS核心文件內(nèi),你需要另外加入angular-route.min.js腳本。并且創(chuàng)建mainApp模塊的時(shí)候需要添加對(duì)ngRoute的依賴。
下面讓我們具體看看路由的例子來(lái)感受下AngularJs中路由的使用。具體的示例代碼如下:
主頁(yè)面 AngularJsRouteDemo.html
<!DOCTYPE html> <html ng-app="mainApp" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>AngularJs路由演示</title> <script src="http://sandbox.runjs.cn/uploads/rs/376/pbcx3e1z/angular.min.js"></script> <script src="http://sandbox.runjs.cn/uploads/rs/376/pbcx3e1z/angular-route.min.js"></script> <script> (function() { // 設(shè)置當(dāng)前模塊依賴,“ngRoute”,用.NET的解就是給這個(gè)類庫(kù)添加“ngRoute”引用 var mainApp = angular.module("mainApp", ['ngRoute']); mainApp.config(['$routeProvider', function($routeProvider) { // 路由配置 var route = $routeProvider; // 指定URL為“/” 控制器:“l(fā)istController”,模板:“route-list.html” route.when('/list', { controller: 'listController', templateUrl: 'route-list.html' }); // 注意“/view/:id” 中的 “:id” 用于捕獲參數(shù)ID route.when('/view/:id', { controller: 'viewController', templateUrl: 'route-view.html' }); // 跳轉(zhuǎn) route.when("/", { redirectTo: '/list' }); route.otherwise({ redirectTo: '/list' }); }]); //創(chuàng)建一個(gè)提供數(shù)據(jù)的服務(wù)器 mainApp.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: "stackoverflow", url: "http://www.stackoverflow.com/" } ]; return function(id) { //假如ID為無(wú)效值返回所有 if (!id) return list; var t = 0; //匹配返回的項(xiàng)目 angular.forEach(list, function(v, i) { if (v.id == id) t = i; }); return list[t]; } }); // 創(chuàng)建控制器 listController,注入提供數(shù)據(jù)服務(wù) mainApp.controller("listController", ["$scope", "service", function($scope, service) { //獲取所有數(shù)據(jù) $scope.list = service(); }]); // 創(chuàng)建查看控制器 viewController, 注意應(yīng)為需要獲取URL ID參數(shù) 我們多設(shè)置了一個(gè) 依賴注入?yún)?shù) “$routeParams” 通過它獲取傳入的 ID參數(shù) mainApp.controller("viewController", ["$scope", "service", '$routeParams', function($scope, service, $routeParams) { $scope.model = service($routeParams.id || 0) || {}; }]); })() </script> </head> <body> <div><a href="#/list">列表</a></div> <br /> <div ng-view> </div> </body> </html>
列表頁(yè)面 route-list.html
<ul ng-repeat="item in list"> <li><a href="#view/{{item.id}}">{{item.title}}</a></li> </ul>
詳細(xì)頁(yè)面 route-view.html
<div> <div>網(wǎng)站ID:{{model.id}}</div> <div>網(wǎng)站名稱:<a href="{{model.url}}" rel="nofollow">{{model.title}}</a></div> <div>訪問地址:{{model.url}}</div> </div>
3.5 自定義指令
前面我們已經(jīng)介紹過指令了。除了AngularJs內(nèi)置的指令外,我們也可以自定義指令來(lái)供我們程序使用。
如果我們?cè)诔绦蛑行枰獙?duì)DOM操作的話,我們可以使用指令來(lái)完成。下面讓我們來(lái)看下一個(gè)全選復(fù)選框的自定義指令的實(shí)現(xiàn):
<!DOCTYPE html> <html ng-app="mainApp" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>AngularJs 指令演示</title> <script src="http://sandbox.runjs.cn/uploads/rs/376/pbcx3e1z/jquery-1.10.2.min.js"></script> <script src="http://sandbox.runjs.cn/uploads/rs/376/pbcx3e1z/angular.min.js"></script> <script> (function(){ var mainApp = angular.module("mainApp", []); //創(chuàng)建一個(gè)提供數(shù)據(jù)的服務(wù)器 mainApp.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: "stackoverflow", url: "http://www.stackoverflow.com/" } ]; return function (id) { //假如ID為無(wú)效值返回所有 if (!id) return list; var t = 0; //匹配返回的項(xiàng)目 angular.forEach(list, function (v, i) { if (v.id == id) t = i; }); return list[t]; }; }); mainApp.directive('imCheck', [function () { return { restrict: 'A', replace: false, link: function (scope, element) { var all = "thead input[type='checkbox']"; var item = "tbody input[type='checkbox']"; //當(dāng)點(diǎn)擊選擇所有項(xiàng)目 element.on("change", all, function () { var o = $(this).prop("checked"); var tds = element.find(item); tds.each(function (i, check) { $(check).prop("checked", o); }); }); //子項(xiàng)修改時(shí)的超值 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); }); } }; }]); mainApp.controller("dectController", ['$scope', 'service', function ($scope, service) { $scope.list = service(); }]); })() </script> </head> <body> <h2>AngularJs 指令演示</h2> <table ng-controller="dectController" im-check> <thead> <tr> <th><input type="checkbox">選擇</th> <th>網(wǎng)站ID</th> <th>網(wǎng)站名稱</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>
3.6 服務(wù)
在上面的路由例子和自定義指令中都有用到AngularJs中的服務(wù)。我理解AngularJs的服務(wù)主要是封裝請(qǐng)求數(shù)據(jù)的內(nèi)容。就如.NET解決方案的層次結(jié)構(gòu)中的Services層。然后AngularJs中的服務(wù)一個(gè)很重要的一點(diǎn)是:服務(wù)是單例的。一個(gè)服務(wù)在AngularJS應(yīng)用中只會(huì)被注入實(shí)例化一次,并貫穿整個(gè)生命周期,與控制器進(jìn)行通信。即控制器操作$scope對(duì)象來(lái)改變視圖,如果控制器需要請(qǐng)求數(shù)據(jù)的話,則是調(diào)用服務(wù)來(lái)請(qǐng)求數(shù)據(jù)的,而服務(wù)獲得數(shù)據(jù)可以通過Http服務(wù)(AngularJS內(nèi)置的服務(wù))來(lái)請(qǐng)求后端的Web API來(lái)獲得所需要的數(shù)據(jù)。
AngularJS系統(tǒng)內(nèi)置的服務(wù)以$開頭,我們也可以自己定義一個(gè)服務(wù)。定義服務(wù)的方式有如下幾種:
- 使用系統(tǒng)內(nèi)置的$provide服務(wù)
- 使用Module的factory方法
- 使用Module的service方法
在前面的例子我們都是以factory方法創(chuàng)建服務(wù)的,接下來(lái)演示下如何使用$provide服務(wù)來(lái)創(chuàng)建一個(gè)服務(wù),具體的代碼如下所示:
<!DOCTYPE html> <html ng-app="mainApp" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>AngularJs 指令演示</title> <script src="http://sandbox.runjs.cn/uploads/rs/376/pbcx3e1z/jquery-1.10.2.min.js"></script> <script src="http://sandbox.runjs.cn/uploads/rs/376/pbcx3e1z/angular.min.js"></script> <script> (function(){ var mainApp = angular.module("mainApp", []).config(['$provide', function($provide){ // 使用系統(tǒng)內(nèi)置的$provide服務(wù)來(lái)創(chuàng)建一個(gè)提供數(shù)據(jù)的服務(wù)器 $provide.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: "stackoverflow", url: "http://www.stackoverflow.com/" } ]; return function (id) { //假如ID為無(wú)效值返回所有 if (!id) return list; var t = 0; //匹配返回的項(xiàng)目 angular.forEach(list, function (v, i) { if (v.id == id) t = i; }); return list[t]; }; }); }]); mainApp.directive('imCheck', [function () { return { restrict: 'A', replace: false, link: function (scope, element) { var all = "thead input[type='checkbox']"; var item = "tbody input[type='checkbox']"; //當(dāng)點(diǎn)擊選擇所有項(xiàng)目 element.on("change", all, function () { var o = $(this).prop("checked"); var tds = element.find(item); tds.each(function (i, check) { $(check).prop("checked", o); }); }); //子項(xiàng)修改時(shí)的超值 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); }); } }; }]); mainApp.controller("dectController", ['$scope', 'service', function ($scope, service) { $scope.list = service(); }]); })() </script> </head> <body> <h2>AngularJs 指令演示</h2> <table ng-controller="dectController" im-check> <thead> <tr> <th><input type="checkbox">選擇</th> <th>網(wǎng)站ID</th> <th>網(wǎng)站名稱</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>
3.7 過濾器
AngularJs過濾器就是用來(lái)格式化數(shù)據(jù)的,包括排序,篩選、轉(zhuǎn)化數(shù)據(jù)等操作。下面代碼創(chuàng)建了一個(gè)反轉(zhuǎn)過濾器。
<!DOCTYPE html> <html ng-app="mainApp" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>AngularJs 過濾器演示</title> <script src="http://sandbox.runjs.cn/uploads/rs/376/pbcx3e1z/angular.min.js"></script> <script> (function () { var mainApp = angular.module("mainApp", []); // 定義反轉(zhuǎn)過濾器,過濾器用來(lái)格式化數(shù)據(jù)(轉(zhuǎn)化,排序,篩選等操作)。 mainApp.filter('reverse', function() { return function(input, uppercase) { input = input || ''; var out = ""; for (var i = 0; i < input.length; i++) { out = input.charAt(i) + out; } if (uppercase) { out = out.toUpperCase(); } return out; }; }); mainApp.controller("filterController", ['$scope', function($scope) { $scope.greeting = "AngularJs"; }]); })() </script> </head> <body> <div ng-controller="filterController"> <input ng-model="greeting" type="text"><br> No filter: {{greeting}}<br> Reverse: {{greeting|reverse}}<br> Reverse + uppercase: {{greeting|reverse:true}}<br> </div> </body> </html>
3.8 前端模塊化開發(fā)
前面例子中的實(shí)現(xiàn)方式并不是我們?cè)趯?shí)際開發(fā)中推薦的方式,因?yàn)樯厦娴睦佣际前阉械那岸诉壿嫸挤旁谝粋€(gè)Html文件里面,這不利于后期的維護(hù)。一旦業(yè)務(wù)邏輯一復(fù)雜,這個(gè)Html文件將會(huì)變得復(fù)雜,導(dǎo)致跟蹤問題和fix bug難度變大。在后端開發(fā)過程中,我們經(jīng)常講職責(zé)單一,將功能相似的代碼放在一起。前端開發(fā)也同樣可以這樣做。對(duì)應(yīng)的模塊化框架有:RequireJs、SeaJs等。
也可以使用AngularJs內(nèi)置的模塊化來(lái)更好地組織代碼結(jié)構(gòu)。具體的代碼請(qǐng)到本文結(jié)尾進(jìn)行下載。這里給出一張采用模塊化開發(fā)的截圖:
四、總結(jié)
到這里,本文的所有內(nèi)容就結(jié)束了,在后面的一篇文章中,我將分享使用AngularJs實(shí)現(xiàn)一個(gè)簡(jiǎn)易的權(quán)限管理系統(tǒng)。以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Angular.JS中指令ng-if的注意事項(xiàng)小結(jié)
這篇文章主要給大家分享了關(guān)于Angular.JS中指令ng-if的一點(diǎn)注意事項(xiàng),分享出來(lái)供大家參考學(xué)習(xí),文中介紹的還是相對(duì)來(lái)說比較詳細(xì),對(duì)大家具有一定的參考借鑒價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-06-06Angular2使用SVG自定義圖表(條形圖、折線圖)組件示例
這篇文章主要介紹了Angular2使用SVG自定義圖表(條形圖、折線圖)組件,涉及Angular結(jié)合svg進(jìn)行圖表繪制的相關(guān)操作技巧,需要的朋友可以參考下2019-05-05angularjs中使用ng-bind-html和ng-include的實(shí)例
下面小編就為大家?guī)?lái)一篇angularjs中使用ng-bind-html和ng-include的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2017-04-04AngualrJS中每次$http請(qǐng)求時(shí)的一個(gè)遮罩層Directive
AngularJS是一款非常強(qiáng)大的前端MVC框架。接下來(lái)通過本文給大家介紹AngualrJS中每次$http請(qǐng)求時(shí)的一個(gè)遮罩層Directive,本文非常具有參考借鑒價(jià)值,特此分享供大家學(xué)習(xí)2016-01-01詳解如何為你的angular app構(gòu)建一個(gè)第三方庫(kù)
這篇文章主要介紹了詳解如何為你的angular app構(gòu)建一個(gè)第三方庫(kù),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2018-12-12