AngularJS_簡介、特性及基本使用_及其工做原理

轉自:angularJS 的工做原理javascript

轉自:經過<script>標籤引入到 HTML 中那麼此時 Angular 就作爲一個普通的 DOM 節點等待瀏覽器解析css

當瀏覽器解析到這個節點時,發現它是一個 js 文件,那麼瀏覽器會中止解析剩餘的 DOM 節點,開始執行這個js(即angular.js)html

同時 Angular 會設置一個事件監聽器來監聽瀏覽器的 DOMContentLoaded 事件前端

當 Angular 監聽到 DOMContentLoaded 事件時,就會啓動 Angular 應用java

1. 初始化階段angularjs

Angular 開始啓動後,它會查找 ng-app 指令ajax

而後初始化一系列必要的組件(即 $injector、$compile 服務以及 $rootScope),接着從新開始解析 DOM 樹express

2. 編譯、連接階段後端

$compile 服務經過遍歷 DOM 樹的方式查找有聲明指令的 DOM 元素數組

當碰到帶有一個或多個指令的 DOM 元素時,它會排序這些指令(基於指令的priority優先級)

而後使用 $injector 服務查找 和 收集指令的 compile 函數並執行它

每一個節點的編譯方法運行以後,$compile 服務就會調用連接函數。這個連接函數爲綁定了封閉做用域的指令設置監控。這一行爲會建立實時視圖

最後,在$compile 服務完成後,AngularJS 運行時就準備好了

3. 運行階段

Angular提供了本身的事件循環

指令自身會註冊事件監聽器,所以當事件被觸發時,指令函數就會運行在 AngularJS 的 $digest 循環中

$digest 循環會等待 $watch 表達式列表

當檢測到模型變化後,就會調用 $watch 函數,而後再次查看 $watch 列表以確保沒有模型被改變

一旦 $digest 循環穩定下來,而且檢測到沒有潛在的變化了,執行過程就會離開 Angular 上下文而且一般會回到瀏覽器中,DOM 將會被渲染到這裏

當你用瀏覽器去訪問 index.html 的時候,angularJS 作了如下事情去渲染頁面:

1. 加載 html,而後解析成 DOM
2. 加載 angular.js 腳本
3. AngularJS 等待 DOMContentLoaded 事件的觸發
4. AngularJS 尋找 ng-app 指令,根據這個指令肯定應用程序的邊界
5. 使用 ng-app 中指定的模塊配置$injector
6. 使用 $injector 建立 $compile 服務 和 $rootScope 
7. 使用 $compile 服務編譯 DOM 並把它連接到 $rootScope 上
8. ng-init 指令對 scope 裏面的變量 xxx 進行賦值
9. 對錶達式 {{xxx}} 進行替換,因而乎,頁面顯示數據

  • angular 和瀏覽器進行交互,粗略來說分爲 3 個階段:

1. 瀏覽器的事件迴路一直等待着事件的觸發,事件包括用戶的交互操做、定時事件或者網絡事件(如服務器的響應等)

2. 一旦有事件觸發,就會進入到 Javascript 的 context 中,通常經過回調函數來修改 DOM

3. 等到回調函數執行完畢以後,瀏覽器又根據新的 DOM 來渲染新的頁面

  • AngularJS 修改了通常的 Javascript 工做流,而且提供了它本身的事件處理機制

這樣就把 Javascript 的 context 分隔成兩部分

一部分是原生的 Javascript 的 context

另外一部分是 AngularJS 的 context

只有處在 AngularJS 的 context 中的操做才能享受到 Angular 的 data-binding、exception handling、property watching 等服務

可是對於外來者(如原生的 Javascript 操做、自定義的事件回調、第三方的庫等)Angular 也不是一律不接見

可使用 AngularJS 提供的 $apply() 函數,將這些外來者包進 AngularJS 的 context 中,讓 Angular 感知到他們產生的變化

1. 首先,瀏覽器會一直處於監聽狀態,一旦有事件被觸發,就會被加到一個 event queue 中,event queue 中的事件會一個一個的執行

2. event queue 中的事件若是是被 $apply() 包起來的話,就會進入到 AngularJS 的 context 中,這裏的 fn() 是咱們但願在 AngularJS 的 context 中執行的函數

3. AngularJS 將執行 fn() 函數,一般狀況下,這個函數會改變應用的某些狀態

4. 而後 AngularJS 會進入到由兩個小循環組成的 $digest 循環中

一個循環是用來處理 $evalAsync 隊列的

用來 schedule 一些須要在渲染視圖以前處理的操做,一般經過 setTimeout(0) 實現

速度會比較慢,可能會出現視圖抖動的問題

一個循環是處理 $watch 列表的

是一些表達式的集合,一旦有改變發生,那麼 $watch 函數就會被調用

$digest 循環會一直迭代知道 $evalAsync 隊列爲空而且 $watch 列表也爲空的時候,即 model 再也不有任何變化。

5. 一旦 AngularJS 的 $digest 循環結束,整個執行就會離開 AngularJS 和 Javascrip 的 context,緊接着瀏覽器就會把數據改變後的視圖從新渲染出來

這段代碼有了一個 input 來接收用戶的輸入

在用瀏覽器去訪問這個 html 文件的時候,input上的 ng-model 指令會給 input 綁上keydown事件

而且會給 name 變量創建一個 $watch 來接收變量值改變的通知。

在交互階段主要會發生如下一系列事件:

1. 當用戶按下鍵盤上的某一個鍵的時候(好比說A),觸發 input 上的 keydown 事件

2. input 上的指令察覺到 input 裏值的變化,調用 $apply(「name=‘A'」) 更新處於 AngularJS 的 context 中的 model

3. AngularJS 將'A'賦值給 name

4. $digest 循環開始,$watch 列表檢測到 name 值的變化,而後通知 {{name}} 表達式,更新 DOM

5. 退出 AngularJS 的 context,而後退出 Javascript 的 context 中的 keydown 事件

6. 瀏覽器從新渲染視圖

AngularJS

Google 推出的開源的前端 JS 結構化框架,主體是 頁面中的動態數據與內存的讀取

相較於 jQuery

jQuery 是前端函數庫,封裝簡化 DOM 操做

應用

構建單頁面 SPA Web 應用____Single Page Application

將全部的活動侷限於一個 html 頁面 (即便頁面跳轉了,也是在本頁面跳轉)

當頁面中有部分數據發生了變化,不會刷新整個頁面,而是局部刷新

利用的就是 ajax 技術,路由

Web App 應用

餓了麼微信網頁版

後臺管理應用: 阿里雲、土豆後臺、惟品會... ...

特性:

雙向數據綁定

聲明式依賴注入

解耦應用邏輯, 數據模型和視圖

完善的頁面指令

定製表單驗證

Ajax 封裝

老版本 angular-1.2.xx

 

新版本 angular-1.5.xx

 

輸入框的內容,實時顯示到下方:

  • $(function(){
        $('input').keyup(function(){    // 不能使用 change,在失去焦點時觸發
            $('span').html(this.value);
        });
    });
    
    /*************** angular-1.2***************/

<body ng-app>    是 <body ng-app=""> 的簡寫____指向建立模塊的名字

angularJS 沒必要寫一行 js 代碼,便可實現,且速度更快

使用:(ng 是核心模塊,其餘都是功能擴展模塊)

1. 引入 angular.js

<script src='./js/angular-1.2.29/angular.js'></script>

2. ng-app 指令,一般 <body ng-app>____使用 插件 ng-inspector 進行數據查看

告訴 angular 核心,管理 當前標籤 所包含的整個區域

而且自動建立 $rootScope 根做用域對象

3. 在管理的標籤區域內使用 angularJS

ng-model    將當前輸入框的值 與 xx 關聯(屬性名: 屬性值),而且做爲當前做用域對象 $rootScope 的屬性

{{表達式}}    顯示數據,從 當前做用域對象 $rootScope 的指定屬性名上取

一般有一個返回值,能夠放到任何須要的位置,

剖析: 

數據流向

頁面上初始化時無數據____ng-model 是雙向數據綁定

首先是從頁面流向內存,再從內存流向頁面的 angular 表達式 和 angular 指令

② 頁面上初始化時有數據____ng-init="username='SunWuKong'"

ng-init 是單向數據綁定,從頁面 view 流向 model 內存

{{表達式}} 也是單向數據綁定,從內存 model 流向 view 頁面

下載: ng-inspector 插件打開的就是 angularJS 的 內存____最大的對象就是 $rootScope 

數據綁定:

數據從一個地方 A 移動(傳遞)到另外一個地方 B____這個過程由框架去完成

雙向數據綁定(視圖 view <----> model 模型)---- (網頁 <----> 內存)____頁面主要就是 angular 指令 和 angular 表達式

數據能夠從 view 流向 model,也能夠從 model 流向 view

使用 ng-model 使得 頁面 的數據存儲到 內存

單向數據綁定

View-->Model  : ng-init

Model-->View  : {{表達式}} 去內存中獲取數據,渲染到頁面

依賴注入

依賴對象: 完成某個特定功能必需要某個對象才能實現____好比 定義子對象,必須形參 $scope

依賴注入: 依賴對象 以形參的形式 被注入進來使用____聲明式依賴注入 (對應的一個叫 命令式依賴注入'遍歷指定數組每一個元素')

命令式 更注重過程 (解答題)

聲明式 更注重結果,是對命令式的局部包裝 (選擇題)

又因爲代碼壓縮,會改變 形參 的命名,因此必須使用 ["形參", function(形參){...}] 顯示聲明依賴注入

MVC 模式

M: Model, 即模型, 儲存數據的容器, 提供操做數據的方法

在 angular 中爲 scope

V: View, 即視圖, 顯示 Model 的數據, 將數據同步到 Model, 與用戶交互

在 angular 中爲 頁面,包括: html/css/directive/expression

C: Controller, 即控制器, 初始化 Model 數據, 爲 Model 添加行爲方法

在 angular 中爲 angular 的 ng-controller

MVVM 模式

在 MVVM 中 angular 的 controller 再也不是架構的核心

angular 的 controller 只是起輔助做用,用來輔助 $scope 對象,即 VM 層

M: Model, 即數據模型

在 angular 中爲 scope 中的各個數據對象

V: View, 即視圖

在 angular 中爲 頁面

VM: ViewModel, 即視圖模型

在 angular 中爲 scope 對象

根做用域對象

一個 js 實例對象,ng-app 指令會默認建立一個 根做用域對象 $rootSScope

做用域對象

根做用域對象的 屬性和方法 與頁面中的 指令/表達式 是關聯的

控制器對象

用於控制 angularJS 應用數據的 實例對象

ng-controller 指定控制器構造函數____形參必須是 $scope____依賴注入

angular 會自動 new 這個構造函數建立控制器對象

同時 還會建立一個新的做用域對象 $scope ,  它是 $rootScope 的 (繼承關係)子對象____$scope____做用域對象

(不可能用 ng-init 初始化全部對象)

  • API: ng/function/angular.module()____一個參數是獲取,多個參數是建立

能夠在全局位置建立、註冊、獲取 Angular 模塊

全部模塊都必須使用這個機制註冊 才能在應用中生效

使用:

1. 建立模塊對象        <body ng-app="myApp">____ng-app 指向建立模塊的名字

var myModule = angular.module("myApp", []);

2. 生成做用域對象____取代 自定義構造函數

myModule.controller("myController1", function($scope){

$scope.empName = "SunWuKong";

});

myModule.controller("myController2", function($scope){

$scope.empName = "ZhuBaJie";

});

--------------------- 優化 ----------------------鏈式調用 (返回值爲 做用域對象)

angular.module("myApp", []).controller("myController1", function($scope){

$scope.empName = "SunWuKong";

}).controller("myController2", function($scope){    // 隱式聲明依賴注入

$scope.empName = "ZhuBaJie";

});

注意:

js 代碼壓縮時,會改變形參,致使 angular 沒法解析

解決: 顯示聲明依賴注入

angular.module("myApp", []).controller("myController1", ['$scope', function($scope){

$scope.empName = "SunWuKong";

}]).controller("myController2", ['$scope', function($scope){

$scope.empName = "ZhuBaJie";

}]);

  • {{表達式}}

單項數據綁定

若是是變量 會在做用域鏈中尋找變量 {{abc.split("").reverse().join("")}}____ 字符串反轉

還能夠是 {{123}}{{'abc'}}{{true}}

{{null}}、{{undefine}}、{{NaN}}、{{Infinity}} 會被解析成 空串 "",不顯示任何內容 

  • 項目

一個項目下來,首先是 UI 設計頁面效果  

UI 從 14 年開始火,比 美工 高一個檔次  

而後前端工程師分析 UI 設計圖,進行靜態 html 頁面設計 

接下來是,數據的動態展示,與後端交互

而後是用戶的交互,數據的展示

angularJS 開發第一步就是 新建 ng-app="myApp"

ng-controller 實現子做用域對象 $scope

ng-model 實現雙向數據綁定

{{表達式}} 從內存顯示數據到頁面

  • 經常使用指令
  • 點擊事件

<button ng-click="getTotalPrice()">計算</button>

  • 遍歷數組顯示數據____數據有幾個數組就會產生幾個新的做用域

<div>

<h2>人員信息列表</h2>

<ul>

<li  ng-repeat="person  in persons">

{{$index}} ---- {{person.username}} ---- {{person.age}}

{{$first}} ---- 第一個 返回 true

{{$last}} ---- 最後一個 返回 true

{{$odd}} ---- 奇數返回 true,從 1 開始計算

{{$even}} ---- 偶數返回 true,從 1 開始

</li>

</ul>

</div>

 

  • ng-bind 指令 解決數據閃屏:因爲用戶網速很差,第一次打開頁面會看到 {{表達式}}

瀏覽器引擎從上往下解析

由於瀏覽器尚未解析到引入的 angular.js,因此頁面尚未生效,致使了 數據閃屏

<div>

<p>{{123}}</p>

優化爲:

<p ng-bind="123"></p>

</div>

  • ng-show 布爾類型,若是爲 true 則 顯示
  • ng-hide 布爾類型,若是爲 true 則 隱藏

<div>

<button ng-click="switchLike()">切換喜歡</button>

<p ng-show="isLike">我喜歡劉亦菲</p>

<p ng-hide="isLike">劉亦菲喜歡我</p>

</div>

------------------- javascript ------------------

$scope.isLike = true;

$scope.switchLike = function(){

$scope.isLike  = !$scope.isLike ;

};

---------------------------------------- 控制 css 楊樣式 --------------------------------------------------

  • ng-style  動態引用 js 指定的的樣式對象 {"color":"blue", "backgrouond": "red"};

  • ng-mouseenter
  • ng-mouseleave

  • ng-class 動態引用定義的樣式    {"aClass": true, bClass: true};

 

字數統計,實時顯示

  • <html>
        <head>
            <meta charset="UTF-8">
            <style type="text/css">
                textarea {
                    resize: none;
                }
            </style>
        </head>
        <body ng-app="myApp">
            <div ng-controller="MyCtrl" >
                <h2>個性簽名:</h2>
                <textarea cols="30" rows="10" ng-model="words"></textarea>
                <div>
                    <button ng-click="saveWords()">保存</button>
                    <button ng-click="readWords()">讀取</button>
                    <button ng-click="clearWords()">刪除</button>
                </div>
                <p>剩餘字數: <span ng-bind="getCount()"></span></p>
            </div>
            
            <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.5.10/angular.js"></script>
            <script type="text/javascript">
                var limitLength = 100;    // 字數限制 100 字
                //window.onDOMContentLoaded = function(){    // 會報錯 ---- 看上面的工做原理
                    angular.module("myApp", []).controller("MyCtrl", ["$scope", function($scope){ $scope.words = "哈哈"; $scope.getCount = function(){ $scope.wordsLength = limitLength - $scope.words.length; if($scope.words.length > 100){ // 超出字數限制,讓用戶輸入失效 $scope.words = $scope.words.slice(0, limitLength); }; return $scope.wordsLength; }; $scope.saveWords = function(){ sessionStorage.setItem("session_key", JSON.stringify($scope.words)); console.log("已經保存到 sessionStorage "); }; $scope.readWords = function(){ $scope.words = JSON.parse(sessionStorage.getItem("session_key")) || ""; // 若是讀不到,則返回 null console.log("已經讀取 sessionStorage "); }; $scope.clearWords = function(){ sessionStorage.removeItem("session_key"); $scope.words = ""; }; }]); //};
            </script>
        </body>
    </html>

數據的動態展現

  • <html>
        <head>
            <meta charset="UTF-8">
            <style type="text/css">
                textarea {
                    resize: none;
                }
            </style>
        </head>
        <body ng-app="myApp">
            <div ng-controller="MyCtrl" >
                <h2>Hero  </h2>
                
                <div>
                    <input type="text" ng-model="heroName"/>
                    <button ng-click="addHero()">添加</button>
                </div>
                
                <div ng-repeat="each in heros">
                    <input type="checkbox" ng-model="each.isChecked" /><span ng-bind="each.name"></span>
                </div>
                
                <button ng-click="removeHreo()">刪除所選對象</button>
            </div>
            
            <script type="text/javascript" src="https://cdn.bootcss.com/angular.js/1.5.10/angular.js"></script>
            <script type="text/javascript">
                // window.onDOMContentLoaded = function(){    // 會報錯 ---- 看上面的工做原理
                    angular.module("myApp", []).controller("MyCtrl", ["$scope", function($scope){ $scope.heros = [ {"name": "Groot", "isChecked": false}, {"name": "玩錘子的", "isChecked": false}, {"name": "浩克", "isChecked": false}, {"name": "洛基", "isChecked": false} ]; $scope.addHero = function(){ var isExit = false; $scope.heros.forEach(function(each, index){ if(each.name === $scope.heroName){ isExit = true; $scope.heroName = ""; }; }); if($scope.heroName && !isExit){ $scope.heros.unshift({"name": $scope.heroName, "isChecked": false}); $scope.heroName = ""; }; }; /**** // 方式1 ---- 刪除 數組中不符合條件的元素 $scope.removeHreo = function(){ $scope.heros.forEach(function(each, index){ if(each.isChecked){ $scope.heros.splice(index, 1); // 從 index 開始刪,刪 1 個 $scope.removeHreo(); }; }); }; ****/ // 方式2 ---- 保留 數組中符合條件的元素 $scope.removeHreo = function(){ var tempArr = $scope.heros; $scope.heros = []; tempArr.forEach(function(each, index){ if(!each.isChecked){ $scope.heros.push(each); }; }); }; }]); // };
            </script>
        </body>
    </html>
相關文章
相關標籤/搜索