二識angularJS

  前言:記得三月份時下定決心說天天要更新一篇博客,學習點新東西,實踐下來發現太不現實,生活中的事情不少,再喜歡也不能讓它一件佔據生活的所有吧,因此呢,之後順其天然吧。以前有一篇‘初識angular’由於離職找工做等一系列緣由,擱置了很久,今早看看,繼續寫之前的已經沒法繼續,索性從新開始,有時間再修該以前的吧。javascript

二識angular(基於angular官方文檔)

地址:https://angularjs.org/css

一,基礎:先看html代碼html

<!doctype html>
<html ng-app><!--ng-app聲明頁面的這個部分將基於angular-->
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
  </head>
  <body>
    <div>
      <label>Name:</label>
      <input type="text" ng-model="yourName" placeholder="Enter a name here">
      <!--ng-model將表單和模型聯繫在一塊兒,這裏的即yourname,這樣你在表單中輸入的內容將出如今後文中調用該變量的地方,{{yourName}}-->
      <h1>Hello {{yourName}}!</h1>
    </div>
  </body>
</html>

構建angular應用,首先應該應該引入資源文件,其次,應該聲明,也就是ng-app指令,告訴應用它是基於angular的。第三,angular是經過各類指令來實現的,所以,第三個步驟就是學習各類指令。java

上面代碼中咱們用到了一個ng-mode指令,l它將表單和模型聯繫在一塊兒,可以在應用中‘瞬間’得到表單輸入的內容。好比,上面的代碼,你在表單中輸入的內容會馬上出如今hello的後面;並且,不管yourName變量什麼時候發生改變它的全部引用也會當即更新。react

二,加入一些控制jquery

第一步,咱們實現了一個簡單的數據的雙向綁定,可是,實際的應用場景中,狀況比這複雜的多,很所時候,咱們須要收集,判斷,處理等等。所以,咱們須要加入一些控制。git

數據綁定:data-binding是一種不管model什麼時候改變都會自動更新的方式,就如上文講到的‘瞬間’得到;同時,他也會在視圖發生改變時更新model。這一點讓煩人的dom操做成了一件你不在須要擔憂的事。($scope.$apply();這段代碼暫且放在這裏,它的做用之一就是能夠傳播model的變化,一般狀況下,咱們在頁面中直接加入的ng-model是能夠「瞬間」更新的,可是若是是在jQuery的ajax中,並非瞬間實現數據同步的,咱們須要將改變傳播出去,這樣才能夠起做用。可是,並不提倡濫用這個方法,通常angular JS自帶的方法會默認調用該方法。)angularjs

控制器:controller,暫且叫它控制器吧,它是和dom元素相關的一系列行爲,它讓你將這些行爲用乾淨可讀性強的表單來表達,取代之前的樣板式的經過註冊回調函數,或者監聽模型是否發生改變來更新form。github

簡單的原生JavaScript:不一樣於其餘框架,angular是簡單的JavaScript項目,你不須要有專門的樣板或者調用及繼承來讓你的東西匹配angular,這一點讓你的代碼很容易測試,維護,重用,並且從複雜的樣板式調用中解放出來。web

下面看一個能夠添加未作事項清單的小應用;

html代碼:

<!doctype html>
<html ng-app="todoApp">
    <head>
        <meta charset="utf-8" />
        <script type="text/javascript" src="js/angular.min.js"></script>
        <script type="text/javascript" src="js/todo.js"></script>
        <style>
            .done-true {text-decoration: line-through;color: grey;}
            ul,li{list-style: none;}
        </style>
    </head>
    <body>
        <h2>須要作的事情清單</h2>
        <!--這個控制器內部的元素行爲將被由ng-controller這個命令所指定的控制器TodoListController所控制。-->
        <div ng-controller="TodoListController as todoList">
            <!--{{todoList.todos.length}}{{todoList.todos.length}}數據調用-->
            <span>您共有{{todoList.todos.length}}件須要作的事情,其中的{{todoList.todos.length}}項還未完成</span> [
            <!--ng-click="todoList.archive()"這也是一個方法調用,顯示還未完成的清單列表-->
            <a href="" ng-click="todoList.archive()">僅顯示未完成清單</a> ]
            <ul>
                <li ng-repeat="todo in todoList.todos">
                    <label class="checkbox">
                    <input type="checkbox" ng-model="todo.done">
                    <span class="done-{{todo.done}}">{{todo.text}}</span>
                  </label>
                </li>
            </ul>
            <!--調用方法ng-submit="todoList.addTodo()"-->
            <form ng-submit="todoList.addTodo()">
                <input type="text" ng-model="todoList.todoText" size="30" placeholder="添加你將要作的事情">
                <input class="btn-primary" type="submit" value="添加">
            </form>
        </div>
    </body>
</html>

 (1),ng-controller="TodoListController as todoList"。

    注意這個as,後文咱們調用TodoListController 時只須要使用todolist代替就行了,如:

      ng-submit="todoList.addTodo()

 (2),ng-repeat="todo in todoList.todos"。

    將 todoList.todos用todo來指代,後文可直接todo.xxx的形式來調用todos裏面的數據。

 (3), <span class="done-{{todo.done}}">{{todo.text}}</span>。

    類名中同樣可使用表達式,而且包含在雙引號內部。

.done-true {
  text-decoration: line-through;
  color: grey;
}

 (4),ng-click="todoList.archive()。

    事件調用。

注意看這個方法,語法幾乎就是JavaScript,只是有時候加上了一些屬於angular的方法。好比本例中的angular.forEach()。angular中能夠直接使用JavaScript。

//定義控制器的方法archive,顯示清單庫中全部還未完成的事情。
        todoList.archive = function() {
            var oldTodos = todoList.todos;
            todoList.todos = [];
            angular.forEach(oldTodos, function(todo) {
                if(!todo.done) todoList.todos.push(todo);//若是事件未完成,則加入事件清單裏面;
            });
        };

js代碼:定義了一個模塊todoApp,同時給這個模塊添加了一組數據和三個方法。

angular.module('todoApp', [])
    //全部的行爲控制寫在控制器裏面;
    .controller('TodoListController', function() {
        var todoList = this;//定義當前控制器的對象;
        todoList.todos = [{//數據源
                text: '學習 AngularJS',
                done: true
            },
            {
                text: '建一個 AngularJS app',
                done: false
            }
        ];
        //定義控制器的方法addTodo,添加未完成的事情。
        todoList.addTodo = function() {
            todoList.todos.push({
                text: todoList.todoText,
                done: false
            });
            todoList.todoText = '';
        };
        //定義控制器的方法remaining,還未完成的事情數目
        todoList.remaining = function() {
            var count = 0;
            angular.forEach(todoList.todos, function(todo) {
                count += todo.done ? 0 : 1;
            });
            return count;
        };
        //定義控制器的方法archive,顯示清單庫中全部還未完成的事情。
        todoList.archive = function() {
            var oldTodos = todoList.todos;
            todoList.todos = [];
            angular.forEach(oldTodos, function(todo) {
                if(!todo.done) todoList.todos.push(todo);
            });
        };
    });

三,和後臺交互

深連接(deep link):一個深連接,反應出用戶此刻處在APP的那個流程中,這對於用戶將頁面存爲書籤和發送郵件很方便,往返型的APP能夠自動得到以上這些,可是ajax類型的應用,則不可能實現這些。angular JS將深連接和桌面應用的類APP行爲結合起來。

表單驗證(Form Validation):客戶端的表單驗證是一個好的用戶體驗中很重要的一個版塊。angularJS讓你不用寫JavaScript代碼就能夠聲明驗證規則。經過類名結合布爾值來判斷,實現表單的驗證。

服務端交互(Server Communication):angular JS提供嵌入的服務,這些服務基於XHR和其餘不少不一樣種類的第三方庫提供的後臺。promises可以很好地簡化你的代碼,經過管理異步的回調數據。下面的例子,咱們將經過AngularJS 的AngularFire 庫來爲一個簡單的angular JS APP搭建一個Firebase後臺。

先看代碼:

主頁面,主要加載資源文件和提供顯示視圖的容器,ng-view能夠結合路由配置實現同一個頁面內部不一樣子內容的加載。不一樣的路由配置下,加載不一樣的模板。

<!doctype html>
<html ng-app="project">

    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" type="text/css" href="css/angular.css"/>
        <link rel="stylesheet" href="css/bootstrap.min.css" />
        <link rel="stylesheet" href="css/font-awesome.css" />
        <script type="text/javascript" src="js/jquery-1.9.1.min.js" ></script>
        <script type="text/javascript" src="js/bootstrap.min.js" ></script>
        <script type="text/javascript" src="js/angular.min.js" ></script>
        <script type="text/javascript" src="js/angular-resource.min.js" ></script>
        <script type="text/javascript" src="js/angular-route.min.js" ></script>
        <script src="https://cdn.firebase.com/js/client/2.0.4/firebase.js"></script>
        <script src="https://cdn.firebase.com/libs/angularfire/0.9.0/angularfire.min.js"></script>
        <script type="text/javascript" src="js/project.js" ></script>
        <script type="text/javascript" src="js/project-list.js" ></script>
    </head>
    <body>
        <div class="container">
            <h2>JavaScript Projects</h2>
            <!--咱們經過這個div,做爲加載局部頁面或者視圖的地方。它周圍的頁面會保持靜態,
            當咱們在這個模塊中動態加載時,這樣咱們能夠在一系列對象和表單之間切換,
            來添加新的項目或者編輯已經存在的項目。-->
            <!--動態加載不一樣的子內容,經過路由配置結合模板來實現,這以外的部分,保持靜態-->
            <div ng-view></div>
        </div>
    </body>
</html>

列表模板:經過遍歷取到的數據,生成列表。

<!--ng-model="projectList.search",將輸入域和search屬性綁定,這個選擇器用來選擇只包含用戶輸入的關鍵字的對象。-->
<input type="text" ng-model="projectList.search" class="search-query" id="projects_search" placeholder="Search">
<table>
    <thead>
        <!--表頭-->
        <tr>
            <th>Project</th>
            <th>Description</th>
            <th>
                <!--一個鏈接到/new的路由,這個路由已經在project.js中配置過,
                既然咱們遵循web的精神,沒有必要在連接上註冊回調函數,咱們只是簡單的導航到一個新的路由
                它會自動更新瀏覽器的瀏覽歷史,而且使deep-linking可用。
                可是,不一樣於普通的server round trip application應用(服務器往返應用),這個navigation event會在瀏覽器中被當即渲染-->
                <a href="#!/new"><i class="icon-plus-sign"></i></a>
            </th>
        </tr>
    </thead>
    <!--表格主體-->
    <tbody>
        <!--ng-repeat="project in projectList.projects | filter:projectList.search | orderBy:'name'"
            ng-repeat用來展開一個數據集合,(遍歷),對於集合中的每一條數據,angular都會執行一次生成操做
        -->
        <!--filter,用來選擇一個集合的子集,該子集是包含projectList.search關鍵字的一個集合。
        orderBy,指定子集的排序規則-->
        <tr ng-repeat="project in projectList.projects | filter:projectList.search | orderBy:'name'">
            <!--遍歷生成表格的每一行-->
            <td>
                <a ng-href="{{project.site}}" target="_blank">{{project.name}}</a>
            </td>
            <td>{{project.description}}</td>
            <td>
                <a ng-href="#!/edit/{{project.$id}}"><i class="icon-pencil"></i></a>
            </td>
        </tr>
    </tbody>
</table>

修改或者添加模板:重點是表單驗證。

<!--建立一個名爲myForm的表單,在這裏咱們會聲明驗證規則,來顯示錯誤輸入和不可操做的表單-->
<form name="myForm">
    <!--添加一個error類,當輸入不合法時,$pristine意思是若是表單未被使用,也就是輸入爲空。-->
    <div class="control-group" ng-class="{error: myForm.name.$invalid && !myForm.name.$pristine}">
        <label>Name</label>
        <!--required:當沒有輸入時,將輸入域置爲無效-->
        <input type="text" name="name" ng-model="editProject.project.name" required>
            <!--show這個錯誤信息,當input name有requeired error時-->
        <span ng-show="myForm.name.$error.required && !myForm.name.$pristine" class="help-inline">
        Required {{myForm.name.$pristine}}</span>
    </div>

    <div class="control-group" ng-class="{error: myForm.site.$invalid && !myForm.site.$pristine}">
        <label>Website</label>
        <input type="url" name="site" ng-model="editProject.project.site" required>
        <span ng-show="myForm.site.$error.required && !myForm.site.$pristine" class="help-inline">
        Required</span>
        <span ng-show="myForm.site.$error.url" class="help-inline">Not a URL</span>
    </div>

    <label>Description</label>
    <textarea name="description" ng-model="editProject.project.description"></textarea>

    <br>
    <a href="#!/" class="btn">Cancel</a>
     <!--ng-disabled 將save按鈕置爲不可操做,當表單沒有輸入或者輸入有誤時-->
    <button ng-click="editProject.save()" ng-disabled="myForm.$invalid" class="btn btn-primary">Save</button>
    <button ng-click="editProject.destroy()" ng-show="editProject.project.$id" class="btn btn-danger">Delete</button>
</form>

JavaScript文件:

項目主代碼:project.js。主要包括取數據,路由配置和顯示列表、添加項目、修改項目三個controller的定義。(注意裏面的各類注入的依賴,在function裏面聲明)

//定義module,經過它你能夠安裝(加載)angular已有的服務和定義新的命令,服務和選擇器等等。
angular.module('project', ['ngRoute', 'firebase'])
//模塊能夠依賴於其它模塊,這裏project須要firebase來處理這個應用的可持續。
    .value('fbURL', 'https://ng-projects-list.firebaseio.com/')
    //.value能夠用來定義一個單獨的對象,能夠注入到其它的controllers和servises中去。前面是變量名,後面是值。
    .service('fbRef', function(fbURL) {
        return new Firebase(fbURL)//返回請求地址
    })
    .service('fbAuth', function($q, $firebase, $firebaseAuth, fbRef) {//$firebase firegase提供的一個服務
        var auth;
        return function() {
            if(auth) return $q.when(auth);
            var authObj = $firebaseAuth(fbRef);
            if(authObj.$getAuth()) {
                return $q.when(auth = authObj.$getAuth());
            }
            var deferred = $q.defer();
            authObj.$authAnonymously().then(function(authData) {
                auth = authData;
                deferred.resolve(authData);
            });
            return deferred.promise;
        }
    })
/**
 * Projects是firebase的一個實例,在project模塊中已經定義過了,
 * 它提供對應用進行增長,刪除和更新的方法(接口),
 * 它的目標是將服務器交互抽象化。
 * 它讓controllers集中處理行爲而不是複雜的服務器鏈接之類。
 **/
    .service('Projects', function($q, $firebase, fbRef, fbAuth, projectListValue) {
        var self = this;
        this.fetch = function() {//取數據,也就是和後臺交互。這裏是基於firebase,也能夠是經過其餘形式來進行數據調用,好比ajax
            if(this.projects) return $q.when(this.projects);
            return fbAuth().then(function(auth) {
                var deferred = $q.defer();
                var ref = fbRef.child('projects-fresh/' + auth.auth.uid);
                var $projects = $firebase(ref);
                ref.on('value', function(snapshot) {
                    if(snapshot.val() === null) {
                        //咱們能夠經過將一個對象的值設爲null來刪除它。
                        $projects.$set(projectListValue);
                    }
                    //$asArray()一個方法,以數組形式返回firebase裏面的數據。
                    self.projects = $projects.$asArray();//取到數據並以數組形式返回
                    deferred.resolve(self.projects);
                });

                //Remove projects list when no longer needed.
                ref.onDisconnect().remove();
                return deferred.promise;
            });
        };
    })
    /* 
     * .config()能夠用來對已經存在的服務進行配置,
     * 這裏咱們將對$routeProvider進行配置,來讓它適用於局部路徑。
     * */
    .config(function($routeProvider) {
        var resolveProjects = {
            projects: function(Projects) {
                return Projects.fetch();//獲取數據,依賴於Projects模塊
            }
        };

        $routeProvider
        /**
         * '/'當URL是/的時候,將會加載List.html到view裏,同時和ProjectListController相關聯,
         * 經過閱讀路由定義,你能夠當即獲得一個關於APP結構的概覽。
         * **/
            .when('/', {
                /**
                 * controller定義一個controller function能夠和使用ng-congroller的dom元素關聯
                 * 或者和一個view template經過在路由配置裏面指定從而實現關聯。
                 * **/
                controller: 'ProjectListController as projectList',//聲明controller
                templateUrl: 'list.html',
                resolve: resolveProjects//數據調用
            })
            /**
             * '/edit/:projectId',這個路由定義咱們使用了冒號,咱們能夠經過冒號來讓URL的一個部分能夠被controller調用。(相似於傳參吧)
             * 如今,edit controller可使用projectId做爲參數,來找到須要edit的對象。
             * **/
            .when('/edit/:projectId', {
                controller: 'EditProjectController as editProject',
                templateUrl: 'detail.html',
                resolve: resolveProjects
            })
            .when('/new', {
                controller: 'NewProjectController as editProject',
                templateUrl: 'detail.html',
                resolve: resolveProjects
            })
            //.otherwise()指定,噹噹前路由不知足已經配置的全部路由時要顯示的界面。
            .otherwise({
                redirectTo: '/'
            });
    })
//顯示列表
    .controller('ProjectListController', function(projects) {
        var projectList = this;
        projectList.projects = projects;//把數據源導入
    })
//新增項目
    //能夠經過$location服務,來使用瀏覽器的location對象
    .controller('NewProjectController', function($location, projects) {
        var editProject = this;
        //當視圖中的save按鈕被點擊時,執行
        editProject.save = function() {
            projects.$add(editProject.project).then(function(data) {
                /**
                 * 咱們用.path()方法來改變location的'deep-linking'location。
                 * URL的改變,會當即激活新的路由,而且讓應用顯示對應的view,這裏也就是
                 * **/
                $location.path('/');//添加以後跳轉到默認的列表頁
            });
        };
    })
//修改項目
    .controller('EditProjectController',
    //$routeParams:這裏咱們讓angular注入$routeParams,經過它來使從路由配置中提取出來的參數可用。
        function($location, $routeParams, projects) {
            var editProject = this;
            //projectId:提取URL中的projectId,它容許controller利用應用的deep-linking信息進行加工。(生成其它內容)
            var projectId = $routeParams.projectId,
                projectIndex;

            editProject.projects = projects;
            projectIndex = editProject.projects.$indexFor(projectId);
            editProject.project = editProject.projects[projectIndex];
            //當用戶單擊刪除按鈕時執行。
            editProject.destroy = function() {
                editProject.projects.$remove(editProject.project).then(function(data) {
                    $location.path('/');//刪除以後跳轉到主頁。也就是默認的列表頁
                });
            };

            editProject.save = function() {
                editProject.projects.$save(editProject.project).then(function(data) {
                    $location.path('/');//保存以後跳轉到默認的列表頁
                });
            };
        });

要點分析:

(1),angular.module:這個語句定義一個angular模塊或者說是小的‘應用’,是一個相對獨立的單元,它能夠擁有本身的一系列‘私有物’。

(2),angular.module.value:定義一個獨立的angular對象,他能夠注入到其它的controllers或者service中去,個人理解是相似於js中的靜態變量的感受。

(3),angular.module.service:定義一個服務,能夠注入其它內容,在服務中引用,自己也能夠被引用。

(4),angular.module.factory:和service相似。

(5),angular.module.controller:定義controllers。

(6),angular.module.config:用來對已經存在的服務進行配置。

數據代碼(模擬數據):project-list.js

angular.module('project').value('projectListValue', [{
        name: 'AngularJS',
        site: 'http://angularjs.org',
        description: 'HTML enhanced for web apps!'
    },
    {
        name: 'Angular',
        site: 'http://angular.io',
        description: 'One framework. Mobile and desktop.'
    },
    {
        name: 'jQuery',
        site: 'http://jquery.com/',
        description: 'Write less, do more.'
    },
    {
        name: 'Backbone',
        site: 'http://backbonejs.org/',
        description: 'Models for your apps.'
    },
    {
        name: 'SproutCore',
        site: 'http://sproutcore.com/',
        description: 'A Framework for Innovative web-apps.'
    },
    {
        name: 'Polymer',
        site: 'https://www.polymer-project.org/',
        description: 'Reusable components for the modern web.'
    },
    {
        name: 'Spine',
        site: 'http://spinejs.com/',
        description: 'Awesome MVC Apps.'
    },
    {
        name: 'Cappucino',
        site: 'http://www.cappuccino-project.org/',
        description: 'Objective-J.'
    },
    {
        name: 'Knockout',
        site: 'http://knockoutjs.com/',
        description: 'MVVM pattern.'
    },
    {
        name: 'GWT',
        site: 'http://www.gwtproject.org/',
        description: 'JS in Java.'
    },
    {
        name: 'Ember',
        site: 'http://emberjs.com/',
        description: 'Ambitious web apps.'
    },
    {
        name: 'React',
        site: 'https://facebook.github.io/react/',
        description: 'A JavaScript library for building user interfaces.'
    }
])

四,建立組件

指令(Directives):指令是angular JS中一個獨特而又強大的特色,它讓你建立新的html標籤,只在你的應用範圍內有效。

可重用組件(Reusable Components):咱們經過指令來建立可重用組件,組件讓你可以隱藏複雜的dom結構,css和行爲,它讓你只關注應用作什麼或者應用的外觀中的一個方面。將二者分開來處理。

本地化(Localization):本地化是一個嚴謹或者說正式的APP中很是重要的一個方面。angular js的本地化感知過濾器和阻擋指令給你獨特的模塊,讓你的應用適用於全部區域。

先看一個示例代碼:

html:

<!DOCTYPE html>
<!--ng-app激活這個頁面區域的APP 模塊,這個模塊包括BeerCounter controller,並且依賴於components module
它包含html擴展命令<tabs>和<pane>組件。-->
<html ng-app="app">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <link rel="stylesheet" href="../backend/css/bootstrap.min.css" />
        <link rel="stylesheet" href="../backend/css/font-awesome.css" />
        <script type="text/javascript" src="../backend/js/jquery-1.9.1.min.js" ></script>
        <script type="text/javascript" src="../backend/js/bootstrap.min.js" ></script>
        <script type="text/javascript" src="../js/angular.min.js" ></script>
        <script src="components.js"></script>
        <script src="app.js"></script>
    </head>

    <body class="container">
        <!--咱們經過普通的tabs擴展了html的標籤庫,它抽象了渲染tabs所須要的複雜的html結構和相關行爲,
        生成一個可讀性強的視圖,同時也是一個可重用的序列。-->
        <tabs>
            <!--組件能夠以html屬性的形式攜帶參數,在這裏,title屬性指定了tabs的文本;
                Localization一個演示angular中num,data等的數據格式和本地化;
                兩個pane分別表明兩個tab切換卡的內容。一個標題爲Localization,另外一個標題爲Pluralization
            -->
            <pane title="Localization">
                <span>Date: {{ '2012-04-01' | date:'fullDate' }}</span><br>
                <span>Currency: {{ 123456 | currency }}</span><br>
                <span>Number: {{ 98765.4321 | number }}</span><br>
            </pane>
            <!--Pluralization一個演示angular多元化的例子,注意數量改變時,beer的不一樣形式。-->
            <pane title="Pluralization">
                <!--咱們經過BeerCounter controller來創建基於本地的計數規則-->
                <div ng-controller="BeerCounter">
                    <div ng-repeat="beerCount in beers">
                        <!--ng-pluralize指令爲每一個區域選擇正確的顯示格式,不一樣於英語,其它語言一般都有基於包含項目數組的複雜的顯示規則
                        count="beerCount",綁定到number屬性,它成爲選擇顯示格式的選擇器
                        when="beerForms"綁定到多元化規則,這些規則會由於語言個地區的不一樣組合而不一樣。-->
                        <ng-pluralize count="beerCount" when="beerForms"></ng-pluralize>
                    </div>
                </div>
            </pane>
        </tabs>
    </body>

</html>

去掉註釋和引用後的主體html代碼:

<body class="container">
        <tabs>
            <pane title="Localization">
                <span>Date: {{ '2012-04-01' | date:'fullDate' }}</span><br>
                <span>Currency: {{ 123456 | currency }}</span><br>
                <span>Number: {{ 98765.4321 | number }}</span><br>
            </pane>
            <pane title="Pluralization">
                <div ng-controller="BeerCounter">
                    <div ng-repeat="beerCount in beers">
                        <ng-pluralize count="beerCount" when="beerForms"></ng-pluralize>
                    </div>
                </div>
            </pane>
        </tabs>
    </body>

html中已經初始化了應用,這裏簡要分析下這段代碼:這段代碼用到了兩個自定義標籤,tabs和pane。tabs是咱們常見的切換卡,代碼中經過pane的title屬性將本身和tabs標題關聯起來。title的值就是它所對應的tabs的標題。因此,簡要抽象這個組件的話能夠當作下面的內容:

<tabs>
    <pane title='我是選項卡標題'>
          <div>我是選項卡內容</div>
    </pane>
    <pane title='標題1'>
          <div>我是選項卡內容</div>
    </pane>
    <pane title='標題2'>
         <div>我是選項卡內容</div>
    </pane>
</tabs>

JavaScript:

components.js

這個文件中定義了兩個組件,tabs和pane。pane包含在tabs之中。pane之中調用了tabs的controller,因此能夠在內部調用它的方法,即addPane();

angular.module('components', [])
//經過module的.directive()方法來爲咱們的應用定義新的標籤,好比這裏定義了tabs標籤,
    .directive('tabs', function() {
        return {
            //restrict定義html形式,是E的話,組件只能是el形式
            restrict: 'E',
//            指定當angular使用擴展的標籤替換tabs時它應該將原始內容放置於由ng-transclude指令指定的位置.
            transclude: true,
//            組件須要私有的scope,以便它的視圖屬性不會忽然在tabs以外被修改,
//            若是你確實須要暴露內容,你能夠聲明input/output 的內容,這一點能夠參考後文的pans的定義
            scope: {},
//            和應用同樣,組件也能夠擁有一個controllers,來提供組件的行爲,$scope爲組件的scope, $element爲組件所在的元素
            controller: function($scope, $element) {
//                $scope組件的scope
//                $element要放置組件的元素,調用組件時傳入。
                var panes = $scope.panes = [];
//                發佈一個select()方法,用來在tab之間切換視圖。
                $scope.select = function(pane) {
                    angular.forEach(panes, function(pane) {
                        pane.selected = false;//經過布爾值控制是否被選中。這裏是將全部的pane都設爲非選中狀態
                    });
                    pane.selected = true;//當前傳入的這個設爲選中狀態
                }
//                組件一般須要結合在一塊兒,造成一個單元,在這裏,咱們的pane標籤,將經過addPane()方法,將本身註冊到它的容器<tabs>裏面。
                this.addPane = function(pane) {
                    if(panes.length == 0) $scope.select(pane);
                    panes.push(pane);
                }
            },
//            將被瀏覽器渲染替換tabs裏面的內容,注意,模板內部也可使用指令
            template: '<div class="tabbable">' +
                '<ul class="nav nav-tabs">' +
//                ng-class="{active:pane.selected}"咱們建立active類名,來爲處於激活狀態的tab設置樣式。
                '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">' +
                '<a href="" ng-click="select(pane)">{{pane.title}}</a>' +
                '</li>' +
                '</ul>' +
//                ng-transclude標記tabs的內容將會放置在哪裏
                '<div class="tab-content" ng-transclude></div>' +
                '</div>',
//                replace: true告訴angular tabs將會被模板替換,而不是放在它以後
            replace: true
        };
    })

    .directive('pane', function() {
        return {
//            require: '^tabs',說明pane組件必須在tabs組件的內部,這讓pane組件可以使用tabs組件的方法,在這裏也就是addPane();
            require: '^tabs',
            restrict: 'E',
            transclude: true,
            scope: {
                title: '@'
            },
            link: function(scope, element, attrs, tabsController) {
//            tabsController.addPane(scope);咱們以前說過,咱們須要tabs做爲咱們的容器,這裏咱們傳遞它的實例
                tabsController.addPane(scope);
            },
            template: '<div class="tab-pane" ng-class="{active: selected}" ng-transclude>' +
                '</div>',//將替換pane標籤的內容
            replace: true
        };
    })

app.js

 這是app模塊的定義,這裏注入了對於components的依賴,這就保證了咱們能夠在應用中使用本身定義的指令;同時,這個文件中也定義了多元化規則,好比,是英語時如何顯示,其它語言時又如何顯示。

//app模塊聲明瞭一個對components模塊的依賴,這確保了components模塊中的指令,同時也會被加載到應用中.
angular.module('app', ['components'])
//$locale服務包含了一系列和本地化相關的內容,是每一種語言,本地化的混合體.
    .controller('BeerCounter', function($scope, $locale) {
//設置beers的計數數組,咱們將會迭代這個數組,而後看beers的變化狀況,也就是本地化
        $scope.beers = [0, 1, 2, 3, 4, 5, 6];
//$locale.id == 'en-us':基於本地狀況建立不一樣的多元化規則,在真實的應用中,咱們會加載包含每種語言本地化和相關規則的模塊。
        if($locale.id == 'en-us') {
            //$scope.beerForms 適應於英語的多元化規則。
            $scope.beerForms = {
                0: 'no beers',
                one: '{} beer',
                other: '{} beers'
            };
        } else {
            $scope.beerForms = {
                0: 'žiadne pivo',
                one: '{} pivo',
                few: '{} pivá',
                other: '{} pív'
            };
        }
    });

總結:這篇文章基於angular官方文檔,從angular的基礎,加入一些控制,和後臺交互以及建立組件四個方面簡單的介紹了angular。目的在於對angular有一個初步的比較全面的認識。由於剛開始接觸,說的可能有點片面,也不能很好的作一個系統的總結,後期再慢慢補充,不足之處,歡迎提出!

相關文章
相關標籤/搜索