[后端人員耍前端系列]AngularJs篇:30分鍾快速掌握AngularJs


一、前言

  對於前端系列,自然少不了AngularJs的介紹了。在前面文章中,我們介紹了如何使用KnockoutJs來打造一個單頁面程序,后面一篇文章將介紹如何使用AngularJs的開發一個單頁面應用程序。在開始使用AngularJs開發SPA之前,我覺得有必要詳細介紹下AngularJs所涉及的知識點。所有也就有了這篇文章。

二、AngularJs介紹

  AngularJS是Google推出的一款Web應用開發框架。它提供了一系列兼容性良好並可擴展的服務,包括數據綁定、DOM操作、MVC和依賴注入等特性。相信下面圖片可以更好地詮釋AngularJs具體支持哪些特性。

   從上圖可以發現,AngularJs幾乎支持構建一個Web應用的所有內容——數據綁定、表單驗證、路由、依賴注入、控制器、模板和視圖等。

  但並不是所有的應用都適合用AngularJs來做。AngularJS主要考慮的是構建CURD應用,但至少90%的Web應用都是CURD應用。哪什么不適合用AngularJs來做呢? 如游戲、圖像界面編輯器等應用不適合用AngularJs來構建。

三、AngularJS核心知識點

  接下來,我們就詳細介紹了AngularJS的幾個核心知識點,其中包括:

  • 指令(directive)和 數據綁定(Data Binding)
  • 模板(Module)
  • 控制器(Controller)
  • 路由(Route)
  • 服務(service)
  • 過濾器(Filter)

3.1 指令和數據綁定

  在沒有使用AngularJs的Web應用,要實現前台頁面邏輯通過給HTML元素設置ID,然后使用Js或Jquery通過ID來獲取HTML DOM元素。而AngularJS不再需要給HTML元素設置ID,而是使用指令的方式來指導HTML元素的行為。這樣做的好處是開發人員看到HTML元素以及指令(Directive)就可以理解其行為,而傳統設置Id的方式並不能給你帶來任何有用的信息,你需要深入去查看對應的Js代碼來理解其行為。

  上面介紹了這么多,好像沒有正式介紹指令是什么呢?光顧着介紹指令的好處和傳統方式的不同了。指令可以理解為聲明特殊的標簽或屬性。AngularJs內置了很多的指令,你所看到的所有以ng開頭的所有標簽,如ng-app、ng-init、ng-if、ng-model等。

ng-app:用於標識頁面是一個AngularJs頁面。一般加載HTML的根對象上。

ng-init 用於初始化了一個變量

ng-model:用戶在Property和Html控件之間建立雙向的數據綁定(Data Binding)。這樣Html控件的值改變會反應到Property上,反過來也同樣成立。

AngularJs通過表達式的方式將數據綁定到HTML標簽內。AngularJs的表達式寫在雙大括號內:{{expression}}

  下面具體看一個指令的例子:

<!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 = '歡迎學習AngularJS'">
    <div>
        Name: <input type="text" ng-model="name" /> {{name}}
    </div>
    <script src="/Scripts/angular.min.js"></script>
</body>
</html>

  效果在線預覽:點擊此運行

  從在線預覽的頁面可以發現,當我們改變輸入框的值時,對應的改變會反應到name屬性上,從而反應到表達式的值。AngularJs中雙向綁定的使用主要是靠ng-model指令來完成的。前面說的都是一些AngularJs內置的指令,其實我們也可以自定義指令。關於這部分內容將會在后面介紹到。

3.2 模板

  在Asp.net MVC中提供了兩種頁面渲染模板,一種是Aspx,另一種是Razor.然而Asp.net MVC的這兩種模板都是后端模板,即頁面的渲染都是在服務端來完成的。這樣不可避免會加重服務器端的壓力。AngularJs的模板指的是前端模板。AngularJS有內置的前端模板引擎,即所有頁面渲染的操作都是放在瀏覽器端來渲染的,這也是SPA程序的一個優勢所在,所有前端框架都內置了前端模板引擎,將頁面的渲染放在前端來做,從而減輕服務端的壓力。

  在AngularJs中的模板就是指帶有ng-app指令的HTML代碼。AngularJs發現Html頁面是否需要用AngularJs模板引擎去渲染的標志就是ng-app標簽。

  在AngularJs中,我們寫的其實也並不是純的Html頁面,而是模板,最終用戶看到的Html頁面(也就是視圖)是通過模板渲染后的結果

  下面來看下模板的例子:

<!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() {
              // 創建模塊
                var mainApp = angular.module("mainApp",[]);
               // 創建控制器,並注入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 控制器

  其實模板中的例子中,我們就已經定義了名為"tempController"的控制器了。接下來,我們再詳細介紹下AngularJs中的控制器。其實AngularJs中控制器的作用與Asp.net MVC中控制器的作用是一樣的,都是模型和視圖之間的橋梁。而AngularJs的模型對象就是$scope。所以AngularJs控制器知識$scope和視圖之間的橋梁,它通過操作$scope對象來改變視圖。下面代碼演示了控制器的使用:

<!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() {
              // 創建模塊
                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,是因為AngularJs除了支持雙向綁定外(即MVVM特點),還支持路由。在之前介紹的KnockoutJs實現的SPA中,其中路由借用了Asp.net MVC中路由機制。有了AngularJs之后,我們Web前端頁面完全可以不用Asp.net MVC來做了,完全可以使用AngularJs框架來做。

  單頁Web應用由於沒有后端URL資源定位的支持,需要自己實現URL資源定位。AngularJs使用瀏覽器URL"#"后的字符串來定位資源。路由機制並非在AngularJS核心文件內,你需要另外加入angular-route.min.js腳本。並且創建mainApp模塊的時候需要添加對ngRoute的依賴。

  下面讓我們具體看看路由的例子來感受下AngularJs中路由的使用。具體的示例代碼如下:

主頁面 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() {
            // 設置當前模塊依賴,“ngRoute”,用.NET的解就是給這個類庫添加“ngRoute”引用
            var mainApp = angular.module("mainApp", ['ngRoute']);
            mainApp.config(['$routeProvider', function($routeProvider) {
                // 路由配置
                var route = $routeProvider;
                // 指定URL為“/” 控制器:“listController”,模板:“route-list.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.when("/", { redirectTo: '/list' });
                route.otherwise({ redirectTo: '/list' });
            }]);

            //創建一個提供數據的服務器
            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為無效值返回所有
                    if (!id) return list;
                    var t = 0;
                    //匹配返回的項目
                    angular.forEach(list, function(v, i) {
                        if (v.id == id) t = i;
                    });
                    return list[t];
                }
            });

            // 創建控制器 listController,注入提供數據服務
            mainApp.controller("listController", ["$scope", "service", function($scope, service) {
                //獲取所有數據
                $scope.list = service();
            }]);

            // 創建查看控制器 viewController, 注意應為需要獲取URL ID參數 我們多設置了一個 依賴注入參數 “$routeParams” 通過它獲取傳入的 ID參數
            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>

列表頁面 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>

  在線預覽地址:點擊此運行

3.5 自定義指令

   前面我們已經介紹過指令了。除了AngularJs內置的指令外,我們也可以自定義指令來供我們程序使用。

如果我們在程序中需要對DOM操作的話,我們可以使用指令來完成。下面讓我們來看下一個全選復選框的自定義指令的實現:

<!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", []);
            //創建一個提供數據的服務器
            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為無效值返回所有
            if (!id) return list;
            var t = 0;
            //匹配返回的項目
            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']";
                //當點擊選擇所有項目
                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);
                });
            }
        };
    }]);
            
            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>網站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>

  演示效果:點擊此運行

 

3.6 服務

   在上面的路由例子和自定義指令中都有用到AngularJs中的服務。我理解AngularJs的服務主要是封裝請求數據的內容。就如.NET解決方案的層次結構中的Services層。然后AngularJs中的服務一個很重要的一點是:服務是單例的。一個服務在AngularJS應用中只會被注入實例化一次,並貫穿整個生命周期,與控制器進行通信。即控制器操作$scope對象來改變視圖,如果控制器需要請求數據的話,則是調用服務來請求數據的,而服務獲得數據可以通過Http服務(AngularJS內置的服務)來請求后端的Web API來獲得所需要的數據。

 AngularJS系統內置的服務以$開頭,我們也可以自己定義一個服務。定義服務的方式有如下幾種:

  • 使用系統內置的$provide服務
  • 使用Module的factory方法
  • 使用Module的service方法

  在前面的例子我們都是以factory方法創建服務的,接下來演示下如何使用$provide服務來創建一個服務,具體的代碼如下所示:

<!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){ // 使用系統內置的$provide服務來創建一個提供數據的服務器
 $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為無效值返回所有
            if (!id) return list;
            var t = 0;
            //匹配返回的項目
            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']";
                //當點擊選擇所有項目
                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);
                });
            }
        };
    }]);
            
        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>網站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>

  具體的運行效果與上面的效果一樣。點擊此運行

3.7 過濾器

   AngularJs過濾器就是用來格式化數據的,包括排序,篩選、轉化數據等操作。下面代碼創建了一個反轉過濾器。

<!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", []);
            
                        // 定義反轉過濾器,過濾器用來格式化數據(轉化,排序,篩選等操作)。
                    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 前端模塊化開發

  前面例子中的實現方式並不是我們在實際開發中推薦的方式,因為上面的例子都是把所有的前端邏輯都放在一個Html文件里面,這不利於后期的維護。一旦業務邏輯一復雜,這個Html文件將會變得復雜,導致跟蹤問題和fix bug難度變大。在后端開發過程中,我們經常講職責單一,將功能相似的代碼放在一起。前端開發也同樣可以這樣做。對應的模塊化框架有:RequireJs、SeaJs等。

也可以使用AngularJs內置的模塊化來更好地組織代碼結構。具體的代碼請到本文結尾進行下載。這里給出一張采用模塊化開發的截圖:

四、總結

   到這里,本文的所有內容就結束了,在后面的一篇文章中,我將分享使用AngularJs實現一個簡易的權限管理系統。

  更多內容參考:

  AngularJS 教程

   AngularJs官網

  本文所有源碼下載:AngularJsQuickStart

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM