转自:angularJS 的工作原理

转自:通过<script>标签引入到 HTML 中那么此时 Angular 就做为一个普通的 DOM 节点等待浏览器解析

当浏览器解析到这个节点时,发现它是一个 js 文件,那么浏览器会停止解析剩余的 DOM 节点,开始执行这个js(即angular.js)

同时 Angular 会设置一个事件监听器来监听浏览器的 DOMContentLoaded 事件

当 Angular 监听到 DOMContentLoaded 事件时,就会启动 Angular 应用

1. 初始化阶段

Angular 开始启动后,它会查找 ng-app 指令

然后初始化一系列必要的组件(即 $injector、$compile 服务以及 $rootScope),接着重新开始解析 DOM 树

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>

AngularJS_简介、特性及基本使用_及其工作原理的更多相关文章

  1. Spring高级特性之三:@Enable*注解的工作原理

    Spring Boot中阐述热插拔技术的时候,简单地提及@Enable*注解.随着多种框架的应用及深入了解,@Enable*这个注解在各种框架中应用相当普及. 那么@Enable*注解工作原理是怎么样 ...

  2. Apollo简介及工作原理

    一.Apollo简介 1.Apollo是携程框架部门研发的分布式配置中心 2.集中化管理应用的不同环境和不同集群的配置 3.配置修改后能够实时推送到应用端 4.具备规范的权限.流程治理等特性 二.Ap ...

  3. zookeeper工作原理、安装配置、工具命令简介

    1.Zookeeper简介 Zookeeper 是分布式服务框架,主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集群管理.分布式应用配置项的管理等等. 2.zo ...

  4. 内存分析_.Net内存原理介绍

    内存原理介绍 1.       .Net应用程序中的内存 1.1.Net内存类型 Windows使用一个系统:虚拟寻址系统.这个系统的作用是将程序可用的内存地址映射到硬件内存中的实际地址上.其实际结果 ...

  5. 1.JSP 简介及工作原理

    1.JSP 简介 JSP(Java Server Pages)是由Sun Microsystems公司倡导.许多公司参与一起建立的一种动态网页技术标准.JSP技术有点类似ASP技术,它是在传统的网页H ...

  6. Android系统Recovery工作原理之使用update.zip升级过程---updater-script脚本语法简介以及执行流程(转)

    目前update-script脚本格式是edify,其与amend有何区别,暂不讨论,我们只分析其中主要的语法,以及脚本的流程控制. 一.update-script脚本语法简介: 我们顺着所生成的脚本 ...

  7. [转载] zookeeper工作原理、安装配置、工具命令简介

    转载自http://www.cnblogs.com/kunpengit/p/4045334.html 1 Zookeeper简介Zookeeper 是分布式服务框架,主要是用来解决分布式应用中经常遇到 ...

  8. Nginx 反向代理工作原理简介与配置详解

    Nginx反向代理工作原理简介与配置详解   by:授客  QQ:1033553122   测试环境 CentOS 6.5-x86_64 nginx-1.10.0 下载地址:http://nginx. ...

  9. OCM_第十九天课程:Section9 —》Data Guard _ DATA GUARD 原理/DATA GUARD 应用/DATA GUARD 搭建

    注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...

随机推荐

  1. win10添加右键打开命令窗口

    新建文件cmd.reg,将下面代码贴入 Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\Directory\Background\she ...

  2. 代码,java_web

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. APPLE-SA-2019-3-25-4 Safari 12.1

    APPLE-SA-2019-3-25-4 Safari 12.1 Safari 12.1 is now available and addresses the following: Safari Re ...

  4. Leetcode#13. Roman to Integer(罗马数字转整数)

    题目描述 罗马数字包含以下七种字符:I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即 ...

  5. day 13 - 1 迭代器

    迭代器 首先我们查看下列类型拥有的所有方法(会显示很多) print(dir([])) print(dir({})) print(dir('')) print(dir(range(10))) #求下上 ...

  6. iTOP-开发板-MiniLinux-C程序调用shell命令

    本文档介绍的是在 linux 系统环境下 linux-C 调用 shell 命令实验步骤,和文档压缩包一起的“iTOP-开发板-MiniLinux-SHELL_V1.0.zip”是 c 程序源码.Li ...

  7. java web中使用mysql语句遇到的问题

    1.插入数据时遇到     Parameter index out of range (1 > number of parameters, which is 0).  的问题 有问题的代码: 改 ...

  8. 可持久化 trie 的简单入门

    可持久化 $trie$  ....又是一个表里不一的东西..... 可持久化 $trie$  的介绍: 和主席树类似的,其实可持久化就是体现在前缀信息的维护上(搞不懂这怎么就叫做可持久化了...) $ ...

  9. python学习第25天

    异常处理 什么是异常?什么是错误? 1,程序中难免出现错误. 错误主要分为两种: 1,语法错误 语法错误是根本上的错误,无法通过PYTHON解释器.完全无法执行,是在程序中不应该出现的错误.无法进行异 ...

  10. 浅析nodejs的buffer类(转)

    最近翻阅了node v0.10.4的buffer类的源代码,收获不少,也很久没有在cnode上发表文章了,想把一些收获分享给大家,有什么错误的地方希望大牛们指正啊. 前阵子有位rrestjs框架的使用 ...