zoukankan      html  css  js  c++  java
  • angularJS进阶阶段(4)


    angularJS进阶阶段(4)

    编译器/$compile

    编译器$compile是一个AngularJS的内置服务,它负责遍历DOM树来查找匹配指令, 并调用指令的实现代码进行处理。
    HTML编译包括3个步骤:

    • 匹配指令
      $compile遍历DOM树,如果发现有元素匹配了某个指令,那么这个指令将被加入 该DOM元素的指令列表中。一个DOM元素可能匹配多个指令。
    • 执行指令的编译函数
      当一个DOM元素的所有指令都找齐后,编译器根据指令的优先级/priority指令进行排序。 每个指令的compile函数被依次执行。每个compile执行的结果产生一个link函数,这些 link函数合并成一个复合link函数。
    • 执行生成的链接函数
      $compile通过执行指令的link函数,将模板和scope链接起来。结果就是一个DOM视图和scope对象模型 之间的动态数据绑定。

    为何将编译和连接两个步骤分开?

    简单说,当数据模型的变化会导致DOM结构变化时,指令就需要分别定义compile()函数和link函数。 例如,ng-repeat指令需要为数据集合中的每个成员复制DOM元素。将编译和链接过程分开可以有效 地提高性能,因为DOM的复制放在compile()里,仅需要执行一次,但链接则发生在每个生成的DOM元素 上,所以指令的link()函数会执行多次。

    指令很少需要compile函数,因为大多数指令考虑的是作用于特定的DOM元素实例,而不是改变DOM 的结构。所以link函数更常用。

    指令/directive

    笼统地说,指令是DOM元素(例如属性、元素、CSS类等)上的标记符,用来告诉AngularJS的HTML编译器 ($compile服务)将特定的行为绑定到DOM元素,或者改变DOM元素。

    指令可以放置在元素名、属性、CSS类名称及备注中。下面是一些等效的触发”ng-bind”指令的写法:

    1
    2
    3
    4
    <span ng-bind="exp"></span>
    <span class="ng-bind: exp;"></span>
    <ng-bind></ng-bind>
    <!-- directive: ng-bind exp -->

    指令的规范化

    AngularJS在进行匹配检测之前,首先对HTML元素的标签和属性名转化成规范的驼峰式字符串:
    1.去除名称前缀的x-和data-
    2.以: , - 或 _ 为分割符,将字符串切分成单词,除第一个单词外,其余单词首字母大写
    3.重新拼接各单词
    例如,下面的写法都等效地匹配ngBind指令:

    1
    2
    3
    4
    5
    <span ng-bind="name"></span> <br/>
    <span ng:bind="name"></span> <br/>
    <span ng_bind="name"></span> <br/>
    <span data-ng-bind="name"></span> <br/>
    <span x-ng-bind="name"></span> <br/>

    所以,在前面的课程中,我们在HTML中使用的ez-duang指令,将被规范为ezDuang, 编译器使用这个规范化的名称与注册的指令进行匹配。

    控制器

    控制器的作用

    简单地说,没有控制器/controller,我们没有地方定义业务模型。
    <div ng-init="sb={name:'somebody',gender:'male',age:28}">

    控制器让我们有机会在scope上定义我们的业务逻辑,具体说,可以使用控制器:
    1.对scope对象进行初始化
    2.向scope对象添加方法

    在模板中声明控制器

    在一个HTML元素上使用ng-controller指令,就可以引入一个控制器对象:
    <div ng-controller="myController">...</div>

    控制器的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //控制器类定义
    var myControllerClass = function($scope){
    //模型属性定义
    $scope.text = "...";
    //模型方法定义
    $scope.do = (){...};
    };
    //在模块中注册控制器
    angular.module('someModule',[])
    controller("myController",myControllerClass);

    控制器的一次性

    控制器构造函数仅在AngularJS对HTML文档进行编译时被执行一次。从这个角度看, 就更容易理解为何将控制器称为对scope对象的增强:一旦控制器创建完毕,就意味着scope对 象上的业务模型构造完毕,此后就不再需要控制器了- scope对象接管了一切。

    控制器对scope的影响

    ng-controller指令总是创建一个新的scope对象:

    在图中,我们看到:
    1.ng-app指令引发$rootScope对象的创建。开始时,它是一个空对象。
    2.body元素对应的scope对象还是$rootScope。ng-init指令将sb对象挂在了$rootScope上。
    3.div元素通过ng-controller指令创建了一个新的scope对象,这个对象的原型是$rootScope。
    4.因为原型继承的关系,在do函数中对sb的引用指向$rootScope.sb。

    $scope对象

    初始化$scope对象

    通常在应用启动时,需要初始化scope对象上的数据模型。我们之前曾使用ng-init指令进行初始化, 而使用控制器则是更为规范的做法。

    请注意,控制器仅仅负责在编译时在scope对象上建立视图对象vm,视图对象和模板的绑定则是由 scope负责管理的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <html ng-app="ezstuff">
    <head>
    <script src="http://lib.sinaapp.com/js/angular.js/angular-1.2.19/angular.min.js"></script>
    </head>
    <body>
    <div ng-controller="ezController">
    <div>name : {{vm.sb.name}}</div>
    <div>gender : {{vm.sb.gender}}</div>
    <div>age : {{vm.sb.age}}</div>
    <div>career : {{vm.sb.career}}</div>
    <div><img ng-src="{{vm.sb.photo}}"></div>
    </div>
    </body>
    </html>
    var ezControllerClass = function($scope){
    //view model
    $scope.vm = {
    sb : {
    大专栏  angularJS进阶阶段(4) name : "Jason Stantham",
    gender : "male",
    age : 48,
    career : "actor",
    photo : "http://b.hiphotos.baidu.com/baike/w%3D268/sign=a03742145bee3d6d22c680cd7b176d41/359b033b5bb5c9eae4c45250d739b6003af3b34a.jpg"
    }
    };
    };
    angular.module("ezstuff",[])
    .controller("ezController",ezControllerClass);

    向scope对象添加方法

    业务模型是动态的,在数据之外,我们需要给业务模型添加动作。在之前建立的业务模型上,我们增加一个随机挑选的方法:shuffle,这个方法负责 从一个小型的名人库中随机的选择一个名人来更新模型的sb属性:

    通过在button上使用ng-click指令,我们将模型的shuffle方法绑定到了鼠标点击 事件上。试着用鼠标点击【shuffle】按钮,我们的模型将从库里随机的选出一个 名人,显示在视图里。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    <html ng-app="ezstuff">
    <head>
    <script src="http://lib.sinaapp.com/js/angular.js/angular-1.2.19/angular.min.js"></script>
    </head>
    <body>
    <div ng-controller="ezController">
    <button ng-click="vm.shuffle();">shuffle</button>
    <div>name : {{vm.sb.name}}</div>
    <div>gender : {{vm.sb.gender}}</div>
    <div>age : {{vm.sb.age}}</div>
    <div>career : {{vm.sb.career}}</div>
    <div><img ng-src="{{vm.sb.photo}}"></div>
    </div>
    </body>
    </html>
    var ezControllerClass = function($scope){
    //view model
    $scope.vm = {
    sb : {
    name : "Jason Stantham",
    gender : "male",
    age : 48,
    career : "actor",
    photo : "http://b.hiphotos.baidu.com/baike/w%3D268/sign=a03742145bee3d6d22c680cd7b176d41/359b033b5bb5c9eae4c45250d739b6003af3b34a.jpg"
    },
    shuffle : (){
    var repo = [
    {name:"Jason Stantham",gender:"male",age:48,career:"actor",photo:"http://b.hiphotos.baidu.com/baike/w%3D268/sign=a03742145bee3d6d22c680cd7b176d41/359b033b5bb5c9eae4c45250d739b6003af3b34a.jpg"},
    {name:"Jessica Alba",gender:"female",age:32,career:"actress",photo:"http://h.hiphotos.baidu.com/baike/w%3D268/sign=ce8cdcb43bdbb6fd255be2203125aba6/b219ebc4b74543a91d7092831c178a82b9011411.jpg"},
    {name:"Nicolas Cage",gender:"male",age:53,career:"actor",photo:"http://f.hiphotos.baidu.com/baike/w%3D268/sign=e97412d2359b033b2c88fbdc2dcf3620/4a36acaf2edda3cc4187b7f600e93901203f9280.jpg"},
    {name:"崔永元",gender:"male",age:48,career:"independent journalist",photo:"http://e.hiphotos.baidu.com/baike/w%3D268/sign=856e3aab34d3d539c13d08c50286e927/8c1001e93901213ff48a548956e736d12f2e952d.jpg"},
    {name:"Sheetal Sheth",gender:"female",age:36,career:"actress",photo:"http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f3627d0333fa828bc52e95b19c762a51/060828381f30e924f7c565374c086e061d95f757.jpg"},
    {name:"Barack Obama",gender:"male",age:58,career:"president",photo:"http://a.hiphotos.baidu.com/baike/w%3D268/sign=2a0045f7f1d3572c66e29bdab2126352/f7246b600c338744cb293d62520fd9f9d72aa03b.jpg"},
    {name:"Владимир Владимирович Путин",gender:"male",age:63,career:"president",photo:"http://h.hiphotos.baidu.com/baike/w%3D268/sign=657e210bb17eca8012053ee1a9239712/8435e5dde71190efa1a915f7cf1b9d16fdfa604c.jpg"}
    ];
    var idx = Math.floor(Math.random()*repo.length);
    $scope.vm.sb = repo[idx];
    }
    };
    };
    angular.module("ezstuff",[])
    .controller("ezController",ezControllerClass);

    服务

    创建服务组件

    在AngularJS中创建一个服务组件很简单, 只需要定一个具有$get方法的构造函数 然后使用模块的provider方法进行登记:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //定义构造函数
    var myServiceProvider = (){
    this.$get = (){
    return ....
    };
    };
    //在模块中登记
    angular.module("myModule",[])
    provider("myService",myServiceProvider);

    可配置的服务

    有时我们希望服务在不同的场景下可以有不同的行为,这意味着服务可以进行配置。

    比如,我们希望小计算器可以根据不同的本地化区域,给计算结果追加货币符号前缀, 那么需要在这个服务创建之前,首先配置本地化区域的值,然后在具体的计算中, 根据这个值选择合适的货币符号。

    AngularJS使用模块的config()方法对服务进行配置,需要将实例化的服务提供者 (而不是服务实例)注入到配置函数中:

    1
    2
    3
    4
    angular.module("myModule",[])
    config(["myServiceProvider",function(myServiceProvider){
    //do some configuration.
    }]);


    友情提醒

    如有疑问和错误之处,请告知程序员小鲁

  • 相关阅读:
    ACM的算法分类 2015-04-16 14:25 22人阅读 评论(0) 收藏
    初学Larevel 2014-08-21 11:24 90人阅读 评论(0) 收藏
    初学PHP&MySQL 2014-05-31 12:40 92人阅读 评论(0) 收藏
    codeforces 570 E. Pig and Palindromes (dp)
    codeforces 570 D. Tree Requests (dfs序)
    poj 2157 Maze (bfs)
    cf 570 C. Replacement (暴力)
    cf 570B B. Simple Game(构造)
    cf 570 A. Elections
    hdu 1429胜利大逃亡(续) (bfs+状态压缩)
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12268068.html
Copyright © 2011-2022 走看看