AngularJS入門案例,angularjs入門
最近公司在搞新項目,web端採用的是angularJS ,關於angularJS是什麼以及它的基本用法我這裡不做過多解釋,因為之後如果要寫的話,再一點點的去講,新人接觸ng都會被它的一些概念所弄的迷糊,我也是剛接觸幾天才把ng中的一些概念他們之間的關係搞清楚,這裡我可能說的有些不正確,也請見諒並指正。本文主要通過一個實際案例給大家講清楚關於模組,控制器,服務,指令等他們之間的關係,並完成一個登入的功能。
首先需要說的是angularJS中是一款基於MVC的前端架構,MVC就是控制器,視圖,資料模型的概念,在我們用struts的時候,資料模型其實就是我們定義在action中的javabean或者欄位,視圖就是jsp或者html 而控制器就是我們的action,這樣他們各司其職共同完成MVC,同理在angularJS中也做了MVC的分解,這是和jquery相比一個比較大的區別,但是我不認為jquery沒有MVC,只是我們平時的開發中並沒有類似的開發習慣,jquery沒有天然的提供這種開發模式所以我們才忽視了,angular提供了這些天然的支援。在angularJS中,控制器是完成一些基本的擷取資訊,跳轉,調用等工作,在控制器中我們會操作model,操作model就等於操作scope,所謂scope我理解的就是用來儲存資料的一個對象,就好比struts我們用的request對象session對象,而applcation對象就等於angular中的rootScope對象。視圖就是html,在html中我們會引入一些公用的組件例如表單,列表,下拉框等,這些ui組件我們通常會使用easyui,在angular中,我們會用指令進行封裝,當然angular提供了一些內建的指令。
這麼說還有一些亂,簡單來說就是,使用者看到 使用了指令的視圖,通過操作指令將資料參數傳遞給了控制器,控制器從scope中擷取相關參數後,調用服務完成具體商務邏輯。
另外還有兩個概念我們細說,1是模組,2是服務。 模組我理解的就是一個包,它將一類具體操作(指令,控制器,服務)做了封裝。再我們想使用某個指令或者控制器的時候只要引入這個模組(包)就可以了。當然一個模組的定義不只說非要包含這些東西,它可以單獨就包含指令,或者就包含控制器,或者就包含服務,例如
<pre name="code" class="javascript">// 定義相關模組 window.routeModule = angular.module('msd.routes',['ngRoute']); window.serviceModule = angular.module('msd.services', ['ngResource']);; window.controllerModule = angular.module('msd.controllers', ['msd.services']); window.diretiveModule = angular.module('msd.directives', ['msd.services', 'msd.controllers']); window.filterModule = angular.module('msd.filters', []); window.cookieModule = angular.module('msd.cookies', ['ngCookies']);
我們不討論他們如何定義是最好的,看具體的項目實施。這些模組之間可以進行依賴和注入。例如在window.diretiveModule = angular.module('msd.directives', ['msd.services', 'msd.controllers']);中就將service和controller注入到了指令模組中。這樣在所有指令裡都能調用到控制器和服務的相關介面;服務簡單來說就是一個函數或者一個介面,它協助我們處理一些商務邏輯。當然也可以理解為一個工具,因為在angular中提供了很多現成的服務例如最常用到的$http服務,通過$http我們可以使用post和get請求。
以上都是一些基本的常識。具體的細節我們之後再說。下面來看一個登入的demo。
首先我們需要引入一些angular的lib,因為我們的demo很簡單,所以就引入了一個js:
<script type="text/javascript" src="../../../lib/angular/angular.js"></script>
除此之外,我們還會將其他的js代碼都分門別類到了其他的JS檔案裡,所以我們也要記得引入(實際開發中我們可能會用到requirJS)這裡我們不搞這麼複雜。
<script type="text/javascript" src="../controller/controller.js" ></script><script type="text/javascript" src="../directive/directive.js" ></script><script type="text/javascript" src="../service/loginService.js" ></script>
從引入中我們看到了我們將控制器,指令,服務都做了分解,這樣維護起來也簡單。整個的目錄結構如下:
首先我們來看login.html檔案:頁面很簡單除了引入的一些js檔案外,我們唯寫了一行指令的代碼,而這個plus-user-form就是一個我們自訂的指令,它是一個ui組件。
<!DOCTYPE html><html ng-app="myApp"> <head> <title>登入</title> <meta charset="UTF-8"> <script type="text/javascript" src="../../../lib/angular/angular.js"></script> <script type="text/javascript" src="../controller/controller.js" ></script> <script type="text/javascript" src="../directive/directive.js" ></script> <script type="text/javascript" src="../service/loginService.js" ></script> </head> <body> <div> <plus-user-form></plus-user-form> </div> </body></html>
在頁面裡我們還需要注意的是在第二行,我們寫了一個ng-app的屬性,它的值是myApp,angular就是通過ng-app作為入口的,一旦它發現有ng-app存在,那它就認為這之下的頁面全部由angularJS來管理。我們給ng-app賦值了myApp 意味著,這個頁面的ui以及商務邏輯處理都屬於myApp模組。剛才說了myapp既然是一個模組,那就類似一個包,這個包下包含控制器,服務等。同理也能找到我們定義的這個指令,下面我們來看如下定義一個模組,開啟controller,js檔案,我們可以看到這樣一行代碼:
var myApp = angular.module('myApp',[]); //這行代碼就是指利用angular提供的module方法建立了一個名為myApp的模組,[]應該是依賴的模組或者服務。
在這個模組裡,首先我們來建立一個控制器,建立控制器的代碼如下,也是在controller.js檔案裡:
myApp.controller("loginController",function($scope,$location,$window,LoginService){$scope.login = function () {if (!$scope.username) {console.log("請輸入使用者名稱");return;}if (!$scope.password) {console.log("請輸入密碼");return;}LoginService.loginDo({'username': $scope.username,'password': $scope.password}).then(function (data) {if (data == null) {console.log("登入異常");} else {if (200 == data) {console.log("登入成功");$window.location.href = "http://www.baidu.com";} else {console.log("失敗");$window.location.href = "http://www.damai.cn";}}});};});
我們通過controller方法建立了一個名稱為loginController的控制器,這個控制器是一個函數,它注入了$scope,$location,$window等內建的服務,另外還注入了LoginService咱們自訂的服務,為什麼這裡可以引入這個LoginSerivce,因為這個LoginService也屬於這個模組,在loginService.js檔案裡我們建立了這個服務。接下來,我們為$scope建立了一個函數login,這個login就類似於action中的介面一樣可以被調用。同理,它也可以定義並一些一些屬性。例如$scope.username就是在scope這個範圍中建立的屬性。我們通過擷取使用者名稱和密碼判斷它是否為空白,如果為空白我們會做提示(其實angularJS提供了很多的校正機制和提示指令這裡我們不細說了)。如果使用者名稱和密碼不為空白我們調用了loginService的loginDo函數,將使用者名稱和密碼傳了過去。在loginDo的內部其實調用的是$http服務去請求後台了。調用$http服務會返回一個promise對象,它有個then方法用來處理回調,在then方法中的data參數代表了本次請求的響應資料。除此之外,它還有success()函數和error函數。這裡我們做了簡單的判斷如果伺服器返回200,我們就跳到百度,如果不是200就跳到大麥網。這樣我們的控制器就完成了,是不是和struts中的action挺類似的,那下面我們再來看一下loginService是如何定義的,開啟LoginService.js檔案,代碼如下:
var myApp = angular.module('myApp');myApp.factory("LoginService",function($http,$q){return {loginDo: function(httpParams){var deferred = $q.defer();$http({method:"post",url: "/angular-war/loginServlet",params:httpParams}).success(function(data, status) {deferred.resolve(data);}).error(function(data, status) {deferred.reject(null);});return deferred.promise;}};});
首先我們通過module方法擷取了myapp這個模組,利用angular提供的factory方法建立了一個名為LoginService的服務(建立服務的方式有很多種例如service(),provider()等這裡我們不細說他們的區別)這個服務引入了$http服務和$q服務,其中http我們都很熟悉了,$q服務我也不太熟,在我們項目裡用到了,百度了一下
通過調用 $q.defer() 可以構建一個新的 deffered 執行個體。deffered 對象用來將 Promise 執行個體與 標記任務狀態(執行成功還是不成功)的 API 相關聯。deffered 對象的方法resolve(value) ——傳入 value 解決派生的 promise。 如果 value 是一個通過 $q.reject 構造的拒絕對象(rejection) , 該promise 將被拒絕。reject(reason) ——拒絕派生的promise,並提供原因 。 這相當於通過 $q.reject構造的拒絕對象(rejection)作為參數傳遞給 resolve。notify(value) ——在 promise 執行的過程中提供狀態更新。 這在 promise 被解決或拒絕之前可能會被多次調用。
姑且先防著,之後再說。然後我們通過post或者get方法調用了伺服器的介面並將結果返回給控制器。
ok,控制器和服務我們都看過了,模組也知道怎麼回事了,頁面咱們也看了,就剩下指令了,指令directive剛才說了,可以理解為一個 UI組件,本身angularJS提供了一些內建的指令但也提供了自訂指令的API,這樣可以讓全世界的人民都來封裝優秀的指令供大家使用。這裡我們只是為了示範所以就隨便寫了寫,開啟direcitve.js檔案,代碼如下:
var myApp = angular.module("myApp");myApp.directive('plusUserForm', function () {return {restrict: "E",replace: true,templateUrl: '/angular-war/resource/js/login/html/plusUserForm.html'};});
關於如何自訂指令以及指令的相關屬性函數都是什麼意思,它可以作為一個專題去說,這裡我們只是簡單的說一下其中restrict代碼這個指令以一種什麼形式顯示在頁面裡,有4個格式分別是E(element) 元素 A(attribute) 屬性 C(class) 類 M(注釋) 其中屬性是預設的,因為屬性的相容性最好。replace就兩個值false或者true 代碼返回的template內容是嵌套在指令中還是覆蓋指令,templateUrl是指這個指令的具體UI頁面。我們這裡使用了plusUserForm這個html。下面我們來看一下這個form我們如何定義的,開啟plusUserForm.html檔案代碼如下:
<form name="userForm" method="post" ng-controller="loginController"> <input name="username" type="text" placeholder="請輸入使用者名稱" ng-model="username" required /> <input name="password" type="text" placeholder="請輸入密碼" ng-model="password" required /> <a ng-click="login()">登入</a></form>
這個form中幾個注意的地方包括我們使用angularJS內容的ng-controller指令,它代表這個form提交後將會提交個這個控制器來處理,而這個loginController我們已經定義好了,在兩個文字框中,我們通過ng-model指令綁定了兩個屬性分別為username和password 這兩個屬性在控制器的scope中是一一對應的。最後在a標籤中我們使用了ng-click這個指令代表一旦我們點擊了超連結就會觸發login函數,這個login函數是在loginController控制器裡定義的。
OK 這樣整個流程我們就說了一遍。最後我們看下背景代碼怎麼寫的,為了方便我寫了一個servlet,代碼如下:
public class LoginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {try {String username = req.getParameter("username");String password = req.getParameter("password");System.out.println("username:"+username+",password:"+password);PrintWriter printWriter = resp.getWriter();printWriter.print(200);printWriter.flush();printWriter.close();} catch (Exception e) {e.printStackTrace();}}}
這樣所有代碼都說完了,我們看下效果,進入首頁面
輸入使用者名稱和密碼後點擊登入,頁面重新導向到了baidu頁面,這樣我們的demo就做完了。
之後如果有時間我再整理其他的相關知識然後分享給大家。