蛙蛙推薦:AngularJS學習筆記

蛙蛙王子發表於2013-08-07

為了降低前端程式碼的數量,提高可維護性,可測試性,學習了下AngularJS,正在準備投入專案開發中。

AngularJS的概念比較多,如果物件導向方面的書理解的不透的話學習起來有些費勁,它的官方有個快速入門不錯,中文版如下

http://www.ituring.com.cn/minibook/303

但除了入門外,要真實的寫專案還是得把模組劃分,依賴關係處理,元件間通訊,檔案目錄安排等問題解決好才能幹活。

根據這個學習目的,寫了個DEMO,地址如下

http://onlytiancai.github.io/codesnip/angular-demo1.html

 

  1. 頁面初始化時有3個蘋果,3個桔子,使用者可以在輸入框裡重新輸入桔子和蘋果的數量,介面會有相應的變化
  2. 定義了兩個模組
    1. common是通用模組,
      1. 包含一個commonErrorMsg的directive用來顯示全域性的錯誤資訊, 通過監聽common.showerror事件來獲取資訊,並讓字型顯示為紅色
    2. myApp是整個單頁面應用的模組,
      1. 包含inputCtrl, statusCtrl兩個controller
      2. 包含fruits, orange, apple三個directive
      3. 包含range的filter
      4. 包含fruitsService的service
  3. 總體依賴關係如下
    1. myApp依賴common
    2. fruits, inputCtrl, statusCtrl都依賴fruitsService
    3. inputCtrl通過事件隱含依賴common
    4. 總體來說上層module依賴底層module,上層controller依賴底層service
  4. fruits是一個自定義的directive,用來顯示所有水果
    1. transclude=True表示它的子元素也受它管理,比如裡面的時蘋果和桔子
    2. 該directive要和inputCtrl進行通訊,以便動態更改水果的數量, 所以它和inputCtrl共同依賴fruitsService,並通過fruitsService的事件進行通訊。
  5. 事件基本是全域性的,所以定義事件時儘量有個名稱空間, 如common.showerror, fruitsService.updated
  6. orange和apple是兩個很普通的directive,其中apple還掩飾了directive裡如何處理自身的UI事件
  7. statusCtrl就監聽fruitsService.updated事件,並更新自己的狀態
  8. inputCtrl裡watch自身UI裡的兩個ng-model,適時呼叫fruitsService的相關方法
    1. 如果介面輸入太大的數字,會向common.showerror傳送訊息,以在介面上提示給使用者 這裡沒有用ng-form自帶的驗證就是為了演示模組間如何通訊
  9. range的filter是彌補ng-repeat的不足,讓它支援類似 x in range(10)的形式
  10. fruitsService純粹是為了directive之間或controller之間通訊和共享資料所設計

HTML程式碼

<!doctype html>
<html ng-app="myApp">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script src="angular.js"></script>
        <script src="angular-demo1.js" charset="utf-8"></script>
        <title>AngularJS Demo</title>
    </head>
    <body>
        <p common:error_msg></p>
        <p ng-controller="statusCtrl">一共有{{apple_count}}個蘋果,{{orange_count}}個桔子。</p>
        <fruits>
            <apple ng-repeat="n in [] | range:apple_count"></apple>
            <orange ng-repeat="n in [] | range:orange_count"></orange>
        </fruits>
        <p ng-controller="inputCtrl">請輸入
        <input type="text" ng-model="apple_count" />個蘋果,
        <input type="text" ng-model="orange_count" />個桔子      
        </p>
    </body>
</html>

 

js程式碼

angular.module('common', []);
angular.module('common').directive('commonErrorMsg', function(){
    return {
        restrict: "A",
        controller: function ($scope, $element, $attrs) {
            $element.css('color', 'red');
            $scope.$on('common.showerror', function (ev, msg) {
                $element.html(msg);
            });
        }
    }
});

var myApp = angular.module('myApp', ['common']);
myApp.directive('fruits', function(fruitsService) {
    return {
        restrict: "E",
        transclude: true,
        replace: true,
        template: '<ul ng-transclude></ul>',
        controller: function ($scope, $element, $attrs) {
            $scope.$on('fruitsService.updated', function () {
                $scope.apple_count = fruitsService.apple_count; 
                $scope.orange_count = fruitsService.orange_count;      
            });
        }
    }
})
.directive('orange', function() {
    return {
        restrict: "E",
        template: '<li>桔子</li>'
    }
})
.directive('apple', function() {
    return {
        restrict: "E",
        template: '<li><a ng-click="show()" href="#">蘋果</a></li>',
        link: function(scope, element, attrs) {
            scope.show = function(){
                alert('我是一個蘋果');
            }; 
        }
    }
})
.controller('statusCtrl', function($scope, fruitsService) {
    $scope.$on('fruitsService.updated', function () {
        $scope.apple_count = fruitsService.apple_count; 
        $scope.orange_count = fruitsService.orange_count;      
    });    
})
.controller('inputCtrl', function($scope, fruitsService, $rootScope) {
    $scope.$watch('apple_count', function (newVal, oldVal, $scope) {
        if (newVal > 10){
            $rootScope.$emit('common.showerror', '蘋果數量太多了');
        }else{
            fruitsService.set_apple_count(newVal);
        }
    }, true);
    $scope.$watch('orange_count', function (newVal, oldVal, $scope) {
        if (newVal > 10){
            $rootScope.$emit('common.showerror', '桔子數量太多了');
        }else{
            fruitsService.set_orange_count(newVal);
        }
    }, true);
    fruitsService.set_apple_count(3);
    fruitsService.set_orange_count(2);
})
.filter('range', function() {
    return function(input, total) {
        total = parseInt(total);
        for (var i=0; i<total; i++)
            input.push(i);
        return input;
    };
})
.service('fruitsService', function ($rootScope) {
    this.set_apple_count = function (apple_count) {
        this.apple_count = apple_count;
        $rootScope.$broadcast('fruitsService.updated');
    };
    this.set_orange_count = function (orange_count) {
        this.orange_count = orange_count;
        $rootScope.$broadcast('fruitsService.updated');
    };
});

下面這篇帖子也很好,關於如何用AngularJS開發大型專案的。

如何組織大型JavaScript應用中的程式碼?

相關文章