GVKun编程网logo

深入解析AngularJS框架中$scope的作用与生命周期(angularjs scope 原理)

30

此处将为大家介绍关于深入解析AngularJS框架中$scope的作用与生命周期的详细内容,并且为您解答有关angularjsscope原理的相关问题,此外,我们还将为您介绍关于AngularJS$s

此处将为大家介绍关于深入解析AngularJS框架中$scope的作用与生命周期的详细内容,并且为您解答有关angularjs scope 原理的相关问题,此外,我们还将为您介绍关于AngularJS $scope 继承性 作用 生命周期、angularjs 1.x支持生命周期、angularjs link compile 与 controller 的区别详解,了解 angular 生命周期、angularjs – 与postLink相当的Angular 2生命周期是什么?的有用信息。

本文目录一览:

深入解析AngularJS框架中$scope的作用与生命周期(angularjs scope 原理)

深入解析AngularJS框架中$scope的作用与生命周期(angularjs scope 原理)

$scope 的使用贯穿整个 Angular App 应用,它与数据模型相关联,同时也是表达式执行的上下文.有了 $scope 就在视图和控制器之间建立了一个通道,基于作用域视图在修改数据时会立刻更新 $scope,同样的 $scope 发生改变时也会立刻重新渲染视图.

有了 $scope 这样一个桥梁,应用的业务代码可以都在 controller 中,而数据都存放在controller 的 $scope 中.

$scope是一个把view(一个DOM元素)连结到controller上的对象。在我们的MVC结构里,这个 $scope 将成为model,它提供一个绑定到DOM元素(以及其子元素)上的excecution context。

尽管听起来有点复杂,但 $scope 实际上就是一个JavaScript对象,controller和view都可以访问它,所以我们可以利用它在两者间传递信息。在这个 $scope 对象里,我们既存储数据,又存储将要运行在view上的函数。

每一个Angular应用都会有一个 $rootScope。这个 $rootScope 是最顶级的scope,它对应着含有 ng-app 指令属性的那个DOM元素。

如果页面上没有明确设定 $scope ,Angular 就会把数据和函数都绑定到这里, 第一部分中的例子就是靠这一点成功运行的。

在这个例子里,我们将使用 $rootScope 。在main.js文件里,我们给这个scope加一个name属性。把这个函数放进app.run函数里执行,我们就保证了它能在应用的其他部分之前被执行。你可以把app.run函数看作是Angular应用的main方法。

rush:js;"> app.run(function($rootScope) { $rootScope.name = "Ari Lerner"; });

现在,我们可以在view的任何地方访问这个name属性,使用模版表达式{{}},像这样:

rush:js;"> {{ name }}

$rootScope

Angular 应用启动并生成视图时,会将根 ng-app 元素与 $rootScope 进行绑定.$rootScope 是所有 $scope 的最上层对象,可以理解为一个 Angular 应用中得全局作用域对象,所以为它附加太多逻辑或者变量并不是一个好主意,和污染 Javascript 全局作用域是一样的.

$scope 的作用

$scope 对象在 Angular 中充当数据模型的作用,也就是一般 MVC 框架中 Model 得角色.但又不完全与通常意义上的数据模型一样,因为 $scope 并不处理和操作数据,它只是建立了视图和 HTML 之间的桥梁,让视图和 Controller 之间可以友好的通讯.

再进一步系统的划分它的作用和功能:

  • 提供了观察者可以监听数据模型的变化
  • 可以将数据模型的变化通知给整个 App
  • 可以进行嵌套,隔离业务功能和数据
  • 给表达式提供上下文执行环境

在 Javascript 中创建一个新的执行上下文,实际就是用函数创建了一个新的本地上下文,在 Angular 中当为子 DOM 元素创建新的作用域时,其实就是为子 DOM 元素创建了一个新的执行上下文.

$scope 生命周期

Angular 中也有一个'事件'的概念,比如当一个绑定了 ng-model 的 input 值发生变化时,或者一个 ng-click 的 button 被点击时,Angular 的事件循环就会启动.事件循环是 Angular 中非常非常核心的一个概念,因为不是本文主旨所以不多说,感兴趣的可以自己看看资料.这里事件就在 Angular 执行上下文中处理,$scope 就会对定义的表达式求值.此时事件循环被启动,Angular 会监控应用程序内所有对象,脏值检查循环也会启动.

$scope 的生命周期有4个阶段:

1. 创建

控制器或者指令创建时,Angular 会使用 $injector 创建一个新的作用域,然后在控制器或指令运行时,将作用域传递进去.

2. 链接

Angular 启动后会将所有 $scope 对象附加或者说链接到视图上,所有创建 $scope 对象的函数也会被附加到视图上.这些作用域将会注册当 Angular 上下文发生变化时需要运行的函数.也就是 $watch 函数,Angular 通过这些函数或者何时开始事件循环.

3. 更新

一旦事件循环开始运行,就会开始执行自己的脏值检测.一旦检测到变化,就会触发 $scope 上指定的回调函数

4. 销毁

通常来讲如果一个 $scope 在视图中不再需要,Angular 会自己清理它.当然也可以通过 $destroy() 函数手动清理.

ng-controller

要明确创建一个$scope 对象,我们就要给DOM元素安上一个controller对象,使用的是ng-controller 指令属性:

rush:js;">

ng-controller指令给所在的DOM元素创建了一个新的$scope 对象,并将这个$scope 对象包含进外层DOM元素的$scope 对象里。在上面的例子里,这个外层DOM元素的$scope 对象,就是$rootScope 对象。这个scope链是这样的:

现在,MyController 给我们建立了一个可以从DOM元素内部直接访问的$scope 对象。下面我们在的这个$scope 里创建一个person对象,在main.js中:

rush:js;"> app.controller('MyController',function($scope) { $scope.person = { name: "Ari Lerner" }; });

现在我们可以在有ng-controller='MyController'属性的DOM元素的任何子元素里访问这个person 对象,因为它在$scope上。 除了一个例外,所有scope都遵循原型继承(prototypal inheritance),这意味着它们都能访问父scope们。对任何属性和方法,如果AngularJS在当前scope上找不到,就会到父scope上去找,如果在父scope上也没找到,就会继续向上回溯,一直到$rootScope 上。

唯一的例外:有些指令属性可以选择性地创建一个独立的scope,让这个scope不继承它的父scope们。

举个例子,假设我们有一个ParentController ,含有一个person 对象,又有一个ChildController 想要访问这个对象:

rush:js;"> app.controller('ParentController',function($scope) { $scope.person = {greeted: false}; });

app.controller('ChildController',function($scope) {
$scope.sayHello = function() {
$scope.person.greeted = true;
}
});

当我们在view里把ChildController 绑定到ParentController 之下,在子元素里我们就能访问ParentController 创建的父scope的属性,像访问ChildController 自己的scope中的属性一样:

rush:js;">
{{ person }}

AngularJS $scope 继承性 作用 生命周期

AngularJS $scope 继承性 作用 生命周期

一、基本概念

  作用域是一个指向应用模型的对象,相当于 MVVM 中的 ViewModel,能绑定数据(属性)和行为(方法),能监控表达式和传递事件,是实现双向绑定的基础,是应用在 HTML (视图) 和 JavaScript (控制器) 之间的纽带,是连接视图和控制器的一个特殊的 JavaScript 对象。

  作用域是一个树型层次结构,与 DOM 标签平行,有根作用域,多个子作用域,子作用域下又有子作用域。所有的应用都有一个 $rootScope,它作用在 ng-app 指令包含的所有 HTML 元素中。$rootScope 可作用于整个应用中。是各个 controller 中 scope 的桥梁。用 rootscope 定义的值,可以在各个 controller 中使用。ng-app 指令可以产生一个根作用域之外,一些 指令会创建新的子作用域,并且进行原型继承,如 ng-repeat、ng-include、ng-switch、ng-view、ng-controller, 另外,用 scope: true 和 transclude: true 创建自定义 directive 也会产生新作用域。

  作用域变量性质,有局部变量和全部变量之分,全局变量可以在方法,或者闭包内引入,而局部变量只能在定义的方法内使用,其他方法引用不到,$rootscope 相当于全部变量,不应在 $rootScope 附加太多的业务逻辑数据(全局),而是用控制器显示的创建 $scope 对象来管理自己相关的逻辑和数据(局部)。

   作用域继承性,子作用域自动继承父作用域的属性和方法,如果自己有就用自己的同名属性和方法。有如下内部关系

    scope.$parent :指向 scope 的父作用域

    scope.$$childHead:指向 scope 的第一个子作用域

    scope.$$childTail:指向 scope 的最后一个子作用域

    scope.$$nextSibling:指向 scope 的下一个相邻作用域

    scope.$$prevSibling:指向 scope 的上一个相邻作用域

  例子:  

<html>
<head>
  <title>Angular JS</title>
</head>
<body>
  <h2>AngularJS Sample</h2>
  <!--绑定ng-app产生$rootscope,还有产生一个当前作用域$scope(shapeController),这里产生两个作用域-->
<!--message和type都显示自己的--> <div ng-app="mainApp" ng-controller="shapeController"> <p>{{message}} <br/> {{type}} </p>
  <!--产生一个子作用域(circleController)-->
  <!--message显示自己的,type没定义,就显示继承过来的type--> <div ng-controller="circleController"> <p>{{message}} <br/> {{type}} </p> </div>
  <!--产生另一个平行子作用域(squareController)-->
  <!--message和type都显示自己的,虽然和根作用域有继承关系--> <div ng-controller="squareController"> <p>{{message}} <br/> {{type}} </p> </div> </div> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script> <script> var mainApp = angular.module("mainApp", []);  //父控制器,产生父作用域 mainApp.controller("shapeController", function($scope) { $scope.message = "In shape controller"; $scope.type = "Shape"; });  //子作用域,没type,用父作用域的type mainApp.controller("circleController", function($scope) { $scope.message = "In circle controller"; });  //另一个平行子作用域,有type用自己的type mainApp.controller("squareController", function($scope) { $scope.message = "In square controller"; $scope.type = "Square"; }); </script> </body> </html>

二、作用域上的 $watch ()、$apply () 方法

1、watch() 

  用于监听模型变化,当模型发生变化,它会提示你的。

  表达式: $watch (watchExpression, listener, objectEquality);

  其参数:

    watchExpression:监听的对象,它可以是一个 angular 表达式如 ''name'', 或函数如 function (){return $scope.name}。

    listener: 当 watchExpression 变化时会被调用的函数或者表达式,它接收 3 个参数:newValue (新值), oldValue (旧值), scope (作用域的引用)。

    objectEquality:是否深度监听,如果设置为 true, 它告诉 Angular 检查所监控的对象中每一个属性的变化. 如果你希望监控数组的个别元素或者对象的属性而不是一个普通的值, 那么你应该使用它。

$scope.name = ''hello'';
var watch = $scope.$watch(''name'',function(newValue,oldValue, scope){
  console.log(newValue);
   console.log(oldValue);
});
$timeout(function(){
  $scope.name = "world";
},1000);

  在后台显示 world,1 秒后,会变成 hello,$timeout 内部会触发 $scope.$apply ()

2、$apply()

  用于传播模型的变化,如果一些 javascript 方法,如 setTimeout,调用了 AngularJS 函数之后,必须调用 $apply。

$scope.test = function() {  
    setTimeout(function () {  
        $scope.$apply(function () {  
            $scope.user = "hello";  
        });  
    }, 2000);  
} 

 不能写成下边的代码,这样不能实现双向数据绑定。

$scope.test = function() {  
    setTimeout(function () {  
        $scope.user = "hello";  
    }, 2000);  
} 

三、作用

  1、提供了观察者可以监听数据模型的变化

  2、可以将数据模型的变化通知给整个 App

  3、可以进行嵌套,隔离业务功能和数据

  4、给表达式提供上下文执行环境

四、$socpe 的生命周期

  scope 的生命周期处理主要包含以下几个阶段:

  1、创建: AngularJS 启动时,会使用 $injector 创建一个根作用域,将作用域传进相应的控制器或指令中

    注意: AngularJS 除了 ng-controller 和 ng-repeat 指令会创建自己的子作用域,一般不会创建自己的 $scope

  2、链接(注册观察者): AngularJS 运行时,指令会创建自己的作用域,所有的 $scope 对象都会链接到视图上,通过注册 $watch 函数来获取数据变化通知

  3、模型状态改变:更新模型状态必须发生在 scope.$apply 方法中才会被观察到。Angular 框架封装了 $apply 过程,无需我们操心。

  4、更新: AngularJS 通过在顶层 $scope 对象执行事件循环,每个自作用域都会执行自己的脏值检测($digest),每个监控函数会检查变化,如果检测到变化,则 $scope 对象触发指定的回调函数

  5、销毁: 当不再需要子作用域时,$socpe 上可以通过使用 $destoy()方法销毁作用域,回收资源。

angularjs 1.x支持生命周期

angularjs 1.x支持生命周期

我目前正在管理一个AngularJS开发项目。有人说,我们需要从目前的1.2移动到至少AngularJS 1.5。我要求移动的一个要求是,我必须提供支持结束1.5的证据,但在多个小时后,在角度网站和多个谷歌搜索找不到任何支持信息的结束。

有没有正式的评论,当安全补丁和错误修复将不再为Angular v1.x开发?

根据Angular开发团队,当Angular的网站的流量超过50%进入Angular 2.0网站时,Angular 1.x的生命周期结束。

Direct quote:

One of the biggest worries was about how long Google was going to support version 1.X. To allay these fears,Google has taken a new approach to determining where the community is at and what they want. The Angular 1.X project will continue to be hosted at angularjs.org. Angular 2.0,Now in Alpha,will be hosted at angular.io.

The team will look at the traffic to both sites,along with GitHub,in order to determine where the community is still invested. This means that if a majority of traffic is still at angularjs.org,the team will continue to focus resources on 1.X. Angular 1.X will not end life until the majority of traffic has moved to 2.0. “We’ll continue releasing Angular 1 releases until the vast majority of you migrate to Angular 2,” said Minar.

上述报价是从2015年3月。一个more recent quote从2015年10月说:

We at Google are actually going to be on Angular 1 for some time,even though we’ve started to adopt Angular 2 internally,” Green said,speaking about Google’s own Angular-based projects.

PS:对于我们还在使用AngularJS 1.x,这里有一个链接,所以你可以添加您的投票Angular 1只需点击以下网站:https://www.angularjs.org

我找不到一个官方公告,当安全补丁和错误修复将不再被开发。最近我发现是从2014年10月,可能不再相关:

Quote:

According to Brad Green of Angular,Angular 1.3 will continue to receive bugfix and security patch support for 18-24 months after the release of version 2.0.

虽然我的意见不是官方的,我期望开发商社区将叉Angular 1.x并继续保持它多年。有太多的大型应用程序写在Angular1.x的顶部,只是放弃一切,冲破了Angular2。

angularjs link compile 与 controller 的区别详解,了解 angular 生命周期

 壹 ❀ 引

我在 angularjs 一篇文章看懂自定义指令 directive 一文中简单提及了自定义指令中的 link 链接函数与 compile 编译函数,并说到两者具有互斥特性,即同时存在 link 与 compile 时 link 不生效。由于上篇博文篇幅问题,实在不好再过多讨论 link,compile,那么本文将围绕三个问题展开,一是再识 link 与 compile 函数,你将知道两者为何互斥;二是了解 link、compile 与 controller 的区别,存在即合理,在合适的场景下应该使用哪个方法;三是了解指令中代码执行顺序,link 与 controller 执行关系,多层指令又会如何执行?那么本文开始。

 贰 ❀ directive 中的 link 与 compile

我们已经知道编译函数 compile 与链接函数 link 互斥,二者只能存在其一,比如下方例子中,link 函数并不会执行:

angular.module(''myApp'', [])
    .controller(''myCtrl'', function ($scope, $q) {}).directive("echo", function () {
        return {
            restrict: ''EA'',
            compile: function () {
                console.log(''开始编译了!'');
            },
            link: function () {
                console.log(''开始给DOM绑定事件数据了!'')//不执行
            }
        }
    })

那这样就产生了一个问题,是不是 compile 存在就不能操作 link 函数了?并不是这样,完整的 compile 函数其实本身就包含了 link 函数,有如下两种写法:

写法一:

angular.module(''myApp'', [])
    .controller(''myCtrl'', function () {})
    .directive(''echo'', function () {
        return {
            restrict: ''EACM'',
            scope: {},
            replace: true,
            controller: function ($scope, $element) {},
            compile: function (tEle, tAttrs, transcludeFn) {
                //这里模板编译完成但还没被成功返回,我们可以对编译后的DOM树加工
                console.log(''编译完成,加工DOM吧'')
                //返回一个函数作为link函数,模板编译已完成,进入链接阶段
                return function postLink(scope, ele, attrs) {
                    console.log(''开始执行链接函数link'');
                };
            }
        }
    })

写法二:

angular.module(''myApp'', [])
    .controller(''myCtrl'', function ($scope) {})
    .directive(''echo'', function () {
        return {
            restrict: ''EACM'',
            scope: {},
            controller: function ($scope, $element) {},
            compile: function () {
                //这里模板编译完成但还没被成功返回,我们可以对编译后的DOM树加工
                console.log(''模板编译完成,可以访问使用指令的dom元素以及元素上的属性了'')

                //返回一个对象作为link函数,只是这个link又分为了两个部分
                return {
                    pre: function (scope, iElement, iAttrs, controller) {
                        //在子元素被链接之前执行(也就是子元素的postLink执行之前),这里执行DOM转换和链接函数不安全
                        console.log(''pre开始执行了'');
                    },
                    post: function (scope, iElement, iAttrs, controller) {
                        // 在子元素被链接之后执行,在这里执行DOM转换和链接函数一样安全
                        console.log(''link开始执行了'');
                    }
                }
            }
        }
    })

在上面这个例子中,compile 返回的整个对象作为 link 函数,只是 link 函数又分为了 pre 与 post 两个阶段,我暂且称为 preLink postLink 函数,其中 postLink 对应的就是我们熟悉的 Link 函数

postLink 我们知道是在 DOM 元素链接阶段完成之后执行,而 preLink 有点特殊,它是在所有指令模板编译完成且子指令 postLink 执行之前执行(这里如果看不懂后面具体会解释),虽然 preLink 函数中也能给指令模板绑定数据方法,但一般不推荐使用 preLink 函数,要么使用 postLink,或者不写 compile 直接使用 Link 函数。

我知道你这里一定有疑问了,preLink 和 postLink 都能给指令绑定事件监听 DOM,官方为啥不推荐使用 preLink,没用设计它干嘛,二者真就一点区别也没有?当然有,这个我们得先介绍 angular 的生命周期,不了解这个还真不好解释。

 肆 ❀ angular 生命周期

通过上文的 compile 与 link 了解,我们大致知道了 angular 生命周期中存在编译阶段与链接阶段两个重要阶段。angular 的指令在 angular 启动前,会以普通文本形式保存在 HTML 中,但当 angular 正式启动,这些指令就会经历编译与链接。

1. 编译阶段

在编译阶段 angular 会找到指令,若指令存在模板则开始编译解析模板,但有个问题,指令模板中也可能存在模板,于是还得编译指令模板中子指令的模板,类似深度遍历。

一旦指令 DOM 编译完成,模板就会返回一个模板函数,我们有机会在指令的模板函数被返回前对编译后的 DOM 树进行修改,这个机会就在我们前面说的 compile 函数里。

直到令和子指令模板 DOM 编译完成,最外层的父指令模板会统一返回一个模板函数,待模板函数返回完成,编译阶段正式结束。

由于 compile 处于 DOM 解析完成且模板函数还未成功返回的阶段,所以 compile 函数执行一定与编译顺序保持一致,满足从上到下,从外到内的先后顺序执行,我们来看例子:

<body ng-controller="myCtrl">
    <div echo1></div>
    <div echo2></div>
    <div echo3></div>
</body>
angular.module(''myApp'', [])
    .controller(''myCtrl'', function ($scope) {})
    .directive(''echo1'', function () {
        return {
            restrict: ''EACM'',
            template:''<span><echo2></echo2></span>'',
            compile: function () {
                console.log(''compile1开始执行'');
            }
        }
    })
    .directive(''echo2'', function () {
        return {
            restrict: ''EACM'',
            compile: function () {
                console.log(''compile2开始执行'');
            }
        }
    })
    .directive(''echo3'', function () {
        return {
            restrict: ''EACM'',
            compile: function () {
                console.log(''compile3开始执行'');
            }
        }
    })

上述例子中,指令 echo1 拥有子指令 echo2 与兄弟 DOM 指令 echo3,直到 echo2 编译完成,echo3 才能编译,那么我们知道 compile 执行与编译阶段保持一致,满足从上到下,从父到子深度遍历的顺序

由于 compile 可以对编译出来的 DOM 进行再加工,所以最终编译出来的 DOM 树可能与你模板中的 DOM 结构不一致,因此不推荐在 compile 阶段做监听 DOM 事件的操作。

2. 链接阶段

在 compile 执行结束,模板函数被返回并传递给了指令中定义的 link 函数,此时开始链接阶段;链接阶段负责将编译阶段编译好的 DOM 树与 scope 相关联,这样 link 函数就能将定义好的数据,事件与 DOM 绑定在一起,实现 DOM 操作与监听。

前面也说了指令也会有子指令,而这个 preLink 则在编译完成(compile)之后子指令链接之前(preLink)执行,所以 preLink 也在 compile 之后,且在子指令的 preLink 与 postLink 之前执行。

postLink 比较特殊,postLink 永远在编译完成且子指令链接之后执行(postLink 之后),所以也是在 compile 之后,且在子指令的 postLink 之后。

有点混乱了,理一理,以单个指令来说,它应该是编译阶段开始 ---DOM 编译成功执行 compile--- 返回模板函数(编译结束)--- 模板函数传递给 link--- 链接阶段开始,DOM 与 scope 关联 --- 执行 pre--- 执行 post--- 链接阶段结束

而当指令包含子指令时,它应该是编译阶段开始 --- 父指令 DOM 编译成功执行父 compile--- 返回模板函数 --- 子指令 DOM 编译成功执行子 compile--- 返回模板函数 --- 模板函数传递给 link--- 链接阶段开始,DOM 与 scope 关联 --- 执行父 pre--- 执行子 pre--- 执行子 post--- 执行父 post--- 链接阶段结束

看个例子:

<body ng-controller="myCtrl">
    <div echo></div>
</body>
angular.module(''myApp'', [])
    .controller(''myCtrl'', function ($scope) {})
    .directive(''echo'', function () {
        return {
            restrict: ''EACM'',
            template:''<span><echo1></echo1></span>'',
            compile: function () {
                console.log(''compile1开始执行'');
                return {
                    pre: function () {
                        console.log(''pre1开始执行'');
                    },
                    post: function () {
                        console.log(''post1开始执行'');
                    }
                }
            }
        }
    })
    .directive(''echo1'', function () {
        return {
            restrict: ''EACM'',
            compile: function () {
                console.log(''compile2开始执行'');
                return {
                    pre: function () {
                        console.log(''pre2开始执行'');
                    },
                    post: function () {
                        console.log(''post2开始执行'');
                    }
                }
            }
        }
    })

compile 与 pre 就像深度遍历,有子就一直往下执行,post 就像回溯,从里往外执行。

3.preLink 与 postLink 的区别

前面我们留下了一个问题,preLink 到底有什么用,我们来看下面这段代码,猜猜会如何执行:

angular.module(''myApp'', [])
    .controller(''myCtrl'', function ($scope) {})
    .directive(''echo'', function () {
        return {
            restrict: ''EACM'',
            template: ''<span><echo1></echo1></span>'',
            link: function (scope) {
                scope.name = ''听风是风'';
            }
        }
    })
    .directive(''echo1'', function () {
        return {
            restrict: ''EACM'',
            template: ''<span>{{describe}}</span>'',
            link: function (scope) {
                scope.describe = ''我的名字是'' + scope.name;
            }
        }
    })

导致 scope.name 无法取到值的原因是,这里的 link 函数就是我们之前提到的 postLink 函数,postLink 函数执行就像回溯,子指令先执行,所以取值的时候父指令还未声明此变量。想要做到父指令给子指令作用域传值,preLink 就能做到这一点:

angular.module(''myApp'', [])
    .controller(''myCtrl'', function ($scope) {})
    .directive(''echo'', function () {
        return {
            restrict: ''EACM'',
            template: ''<span><echo1></echo1></span>'',
            compile: function () {
                return {
                    pre: function (scope) {
                        scope.name = ''听风是风'';
                    },
                    post: function () {

                    }
                }
            }
        }
    })
    .directive(''echo1'', function () {
        return {
            restrict: ''EACM'',
            template: ''<span>{{describe}}</span>'',
            link: function (scope) {
                scope.describe = ''我的名字是'' + scope.name;
            }
        }
    })

那么到这里我们知道了 pre 与 post 的区别,pre 可以利用自己执行顺序的优势给子指令作用域直接传值,但是仍然不推荐这么做,这里我们只是作为知识了解。毕竟指令应该拥有干净隔离的作用域,也不会用到这种传值模式。

 叁 ❀ link、compile、controller 的职责

那么通过上文的介绍,我们知道了 link 与 compile 对应了链接和编译两个阶段,编译函数负责对模板 DOM 进行转换,在作用域同 DOM 链接之前可以手动操作 DOM。在开发中编写自定义指令时这种操作是非常罕见,所以 compile 使用不多。

链接函数负责将作用域和 DOM 进行链接,编译函数会在模板编译完成并同作用域进行链接后被调用,因此它负责设置事件监听器,监视数据变化和实时的更新 DOM,这与 controller 十分类似。

抛开加工 DOM 的 compile 不说,那我们应该在什么情况下使用 controller 和 link 呢,毕竟这两兄弟都能做 DOM 事件监听与数据更新;其实很简单,如果你希望这个指令的属性方法能被其它指令复用,那就将方法属性定义在 controller 中,如果只是希望给指令自己使用,那就加在 link 函数中。

之所以这么说,是因为指令有一个 require 属性,通过 require,我们能将 require 值同名指令的 controller 加入到当前指令中,然后就可以通过 link 函数的第四个参数直接使用被 require 指令 controller 中的属性方法了,来看个例子:

angular.module(''myApp'', [])
    .controller(''myCtrl'', function ($scope) {})
    .directive(''echo'', function () {
        return {
            restrict: ''EACM'',
            template: ''<span><echo1></echo1></span>'',
            controller: function () {
                this.sayName = function (name) {
                    console.log(''我的名字是'' + name);
                }
            }
        }
    })
    .directive(''echo1'', function () {
        return {
            restrict: ''EACM'',
            template: ''<button ng-click="myName(name)">点我</button>'',
            require: ''^echo'',
            link: function (scope, ele, attr, ctrl) {
                console.log(ctrl);
                scope.name = ''听风是风'';
                scope.myName = ctrl.sayName;
            }
        }
    })

可以看到在指令 echo1 中成功注入了指令 echo 的 controller,我们能在 echo1 中直接使用 echo 的方法,这就是为何说如果指令方法需要复用,建议绑在 controller 中的原因。

 肆 ❀ 总

那么到这里,我们知道了 compile 与 link 是互斥关系,如果同时写了两个函数,link 不会执行,这是因为 compile 本身就会返回一个函数作为 link,哪怕你不写返回函数,那也认定你返回了一个空的 link。

其次,我们知道了 pre 与 post 的区别,这两个函数虽然同属于 link 的一部分,但在生命周期中扮演了不同的角色,pre 在子元素链接完成前执行,而 post 在子元素链接完成之后,这样导致了父的 post 反而比子 post 晚一步执行

我们简单介绍了 angular 生命周期中两个重要的过程,编译阶段与链接阶段,通过这两个阶段,也解释了为什么 compile 与 pre 执行像深度遍历,而 post 像回溯的原因。

最后,我们将 controller,link,compile 工作职责做了一个简单介绍,link 与 controller 很像,但如果你想指令属性方法复用,推荐绑定在 controller 上,如果只是指令自己使用,推荐加在 link 上。

最后我还要留一个疑问,为什么在最后的例子中,指令 echo1 想复用指令 echo controller 上的方法,方法 sayName 是绑定在 this 上的,如果绑在 scope 上能不能复用呢?angular 中的 scope 和 this 到底是什么关系?这个我会在下篇博客中好好介绍。

博客已更新  angularjs $scope 与 this 的区别,controller as vm 有何含义? 

那么本文到这里,结束。

angularjs – 与postLink相当的Angular 2生命周期是什么?

angularjs – 与postLink相当的Angular 2生命周期是什么?

我目前正在从Angular.JS(1.5)升级到Angular 2.我在IComponentController中遇到了$postLink方法,我试图弄清楚Angular 2中等效的生命周期钩子是什么.

解决方法

您很可能正在寻找ngAfterViewInit,它在组件及其所有子组件初始化之后触发.

当然,这取决于您的特定用例,因为异步数据加载可能存在一些差异,可能需要以不同方式处理(例如,监视@input()属性上的异步更改,但这是另一个主题).

doc ref:
https://angular.io/guide/lifecycle-hooks#lifecycle-sequence

关于深入解析AngularJS框架中$scope的作用与生命周期angularjs scope 原理的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于AngularJS $scope 继承性 作用 生命周期、angularjs 1.x支持生命周期、angularjs link compile 与 controller 的区别详解,了解 angular 生命周期、angularjs – 与postLink相当的Angular 2生命周期是什么?等相关内容,可以在本站寻找。

本文标签:

上一篇详解JavaScript的AngularJS框架中的表达式与指令(angular js表达式)

下一篇JS判断字符串字节数并截取长度的方法(js判断字符串字节数并截取长度的方法是)