基于angular中的重要指令详解($eval,$parse和$compile)  更新时间:2016年10月21日 10:23:02   投稿:jingxian   下面小编就为大家带来一篇基于angular中的重要指令详解($eval,$parse和$compile)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧 在angular的服务中,有一些服务你不得不去了解,因为他可以说是ng的核心,而今天,我要介绍的就是ng的两个核心服务,$parse和$compile。其实这两个服务讲的人已经很多了,但是100个读者就有100个哈姆雷特,我在这里讲讲自己对于他们两个服务的理解。 大家可能会疑问,$eval呢,其实他并不是一个服务,他是scope里面的一个方法,并不能算服务,而且它也基于parse的,所以只能算是$parse的另一种写法而已,我们看一下ng源码中$eval的定义是怎样的就知道了   $eval: function(expr, locals) { return $parse(expr)(this, locals); }, 相信看完源码大家就明白了吧,好了,现在就开始两种核心服务的讲解了,如果感觉我说的不对的话,欢迎在评论区或者私聊指出,免得祸害其他读者。 再讲这两个服务的时候,我要先讲一个在本贴的概念:上下文 我相信,很多人都听过这个“上下文”,但是可能有点模糊,在我这里给大家解释解释看看大家接不接受这个说法。 还记得angular的数据绑定吗?比如:我现在有个有个叫TestCtrl的控制器,他的内容如下: .controller(‘TestCtrl’, function($scope) {   $scope.test = “Boo!!!” }) 而在html中我们的代码是这样的 {{test}} 那么,大家不用想都知道结果了,页面上肯定会显示 Boo!!!的字样。 但是如果我删掉ng-controller的指令呢?也就是我没有在html申明控制器,你直接绑定{{test}}会如何呢? 结果只有一个,那就是页面啥都没有(ps:因为你申明了ng-app)。讲到这里大家明白了吗? 控制器就相当于一个上下文的容器,真正的上下文其实是$scope,当页面绑定test,如果申明了控制器,当前上下文就是控制器里面的$scope,ng会去找一下你这个控制器的上下文$scope有没有test,如果有,他当然就显示出来了,但是你不申明控制器的时候呢?他的上下文容器就是ng-app了,那么他真正的上下文就是$rootScope,这个时候他就会寻找$rootScope有没有test。 好了,上下文的概念已经讲完了,其实挺容易理解的,基本上和this非常相似 那么言归正传,我们开始讲$parse,首先我们要看的是ng的API文档 var getter = $parse(‘user.name’); var setter = getter.assign; var context = {user:{name:’angular’}}; var locals = {user:{name:’local’}}; expect(getter(context)).toEqual(‘angular’); setter(context, ‘newValue’); expect(context.user.name).toEqual(‘newValue’); expect(getter(context, locals)).toEqual(‘local’); 大家看到的是ng文档里面对于$parse服务性价比最高的几行代码, getter和setter就是大家所熟知的get方法和set方法了,context和locals仅仅是json对象而已,目的就是模拟上下文关系 大家看到的下面四个语句最终都能通过测试,现在我们一个个来分析,分析之前我要解释一遍什么叫$parse $parse服务其实就是一种解析表达式的功能,就像ng-model=“test”,你在html中写这个东西谁知道你ng-model=“test”中,其实你想绑定的是当前控制器(上下文容器)中scope(上下文)中的test里面的值,ng就是通过$parse服务去帮助你解析这个表达式的,所以在调用$parse服务的时候你需要传递上下文对象,让ng知道你是要去哪里的scope(上下文)去找你这个test。 所以我们看到第一行测试代码是这样的: getter(context)).toEqual(‘angular’) //实际上就是 $parse(‘user.name’)(context) 在这个context就是上下文,他能返回“angular“这个字符串的原理就是经过这三步的: 1.获取当前的表达式user.name 2.获取当前的上下文对象{user:{name:’angular’}} 3.在上下问对象中寻找表达式,最终获得“angular“这个字符创 所以这句测试代码是成功的。 我们看第二个方法setter方法 setter(context, ‘newValue’);//实际上就是 $parse(‘user.name’).assign(context, ‘newValue’) expect(context.user.name).toEqual(‘newValue’);//测试数据上下文的值是否被改变 这里的setter方法其实是改变值得方法 1.获取当前的表达式user.name 2.获取当前的上下文对象{user:{name:’angular’}} 3.改变表达式中的值,将上下文对象编程{user:{name:’newValue’}} 于是上下文对象发生了改变,重新用getter方法去获取表达式的时候,上下文已经从{user:{name:’angular’}} –> {user:{name:’newValue’}},最后获取的表达式的值自然就是“newValue”了,所以测试代码也是通过的。 expect(getter(context, locals)).toEqual(‘local’);//实际上就是$parse(‘user.name’)(context, locals) 这里要表现的其实是上下文的替换功能。 在getter的方法中我们不仅可以选择第一个上下文,但是如果我们传递了第二个参数,那么第一个上下文就会被第二个上下文覆盖,注意是覆盖. 1.获取当前的表达式user.name 2.获取当前的上下文对象{user:{name:’angular’}} 3.覆盖当前的上下文{user:{name:’local’}} 4.获取解析之后表达式的值 重新回到$eval这个地方,我们看待$eval源码中可以看出$eval只有get功能,而没有set功能,但是有些时候我们可以选择传递第二个上下文,来达到修改值得效果。 在这里$parse服务就已将说完了,接下来就是$compile ————————————————– 如果你了解了$parse的概念之后,我想$compile也差不多理解了,其实和$parse很像。但是他是解析一段html代码的,他的功能就是将死模板变成活模板,也是指令的核心服务。 比如你有一段html代码 {{test}},如果你将这段代码直接放在html代码里面,它所呈现的内容是怎样的我不说大家也应该懂。这就是死模板了,而所谓的活模板,就是这里面的数据全部经过了数据的绑定 {{test}}会自动找到当前的上下文,来绑定数据。最后显示出来的 就是活模板,也就是经过数据绑定的模板。 $compile(‘死模板’)(上下文对象),这样就将死模板编程了活模板,你就可以对这段活的html代码做操作了,例如增加到当前节点,等等。 但是在指令中,她会返回两个函数pre-link和post-link 第一个执行的是pre-link,它对于同一个指令的遍历顺序是从父节点到子节点的遍历,在这个阶段,dom节点还没有稳定下来,无法做一些绑定事件的操作,但是我们可以在这里进行一些初始化数据的处理。 第二个执行的是post-link,也就是我们常说的link函数,他是从子节点到父节点遍历的,在这个阶段,DOM节点已经稳定下来了,我们一般会在这里进行很多的操作。 以上就是小编为大家带来的基于angular中的重要指令详解($eval,$parse和$compile)全部内容了,希望大家多多支持脚本之家~ 您可能感兴趣的文章: angularjs指令中的compile与link函数详解 Angular中$compile源码分析 Angular的Bootstrap(引导)和Compiler(编译)机制 AngularJs html compiler详解及示例代码 浅谈Angularjs link和compile的使用区别 angular.js指令中的controller、compile与link函数的不同之处 angular 指令 compile parse eval 相关文章 Angular在模板驱动表单中自定义校验器的方法 本章介绍的是如何对模板驱动表单创建自定义校验器,它相比较响应式表单自定义校验器略为复杂一些。接下来通过本文给大家分享Angular在模板驱动表单中自定义校验器的方法,感兴趣的朋友一起看看吧 2017-08-08 Angular angular-file-upload文件上传的示例代码 这篇文章主要介绍了Angular angular-file-upload文件上传的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 2018-08-08 详解Angular父子组件通讯 本文介绍了Angular父子组件是如何通讯的,对此感兴趣的同学,可以参考下,并且亲自实验一下。 2021-05-05 AngularJS入门教程之过滤器用法示例 这篇文章主要介绍了AngularJS过滤器用法,结合实例形式简单的分析了AngularJS过滤器的功能及基本用法,并举例说明了自定义过滤器的实现技巧,需要的朋友可以参考下 2016-11-11 Angular2 父子组件通信方式的示例 本篇文章主要介绍了Angular2 父子组件通信方式的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 2018-01-01 浅谈Angular2 ng-content 指令在组件中嵌入内容 本篇文章主要介绍了浅谈Angular2 ng-content 指令在组件中嵌入内容,具有一定的参考价值,有兴趣的可以了解一下 2017-08-08 Angular中ng-repeat与ul li的多层嵌套重复问题 这篇文章主要介绍了Angular中ng-repeat与ul li的多层嵌套重复问题,需要的朋友可以参考下 2017-07-07 AngularJS中的缓存使用 一个缓存就是一个组件,它可以透明地储存数据,以便以后可以更快地服务于请求。这篇文章主要介绍了AngularJS中的缓存使用,有兴趣的可以了解一下。 2017-01-01 详解Angular 4.x NgTemplateOutlet 这篇文章主要介绍了详解Angular 4.x NgTemplateOutlet,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 2017-05-05 AngularJs自定义服务之实现签名和加密 AngularJS 是一个 JavaScript 框架,它可以通过 标签添加到 HTML 页面。这篇文章主要介绍了AngularJs自定义服务之实现签名和加密的相关资料,需要的朋友可以参考下 2016-08-08 最新评论

在angular的服务中,有一些服务你不得不去了解,因为他可以说是ng的核心,而今天,我要介绍的就是ng的两个核心服务,$parse和$compile。其实这两个服务讲的人已经很多了,但是100个读者就有100个哈姆雷特,我在这里讲讲自己对于他们两个服务的理解。

大家可能会疑问,$eval呢,其实他并不是一个服务,他是scope里面的一个方法,并不能算服务,而且它也基于parse的,所以只能算是$parse的另一种写法而已,我们看一下ng源码中$eval的定义是怎样的就知道了  

$eval: function(expr, locals) {
    return $parse(expr)(this, locals);
   },

相信看完源码大家就明白了吧,好了,现在就开始两种核心服务的讲解了,如果感觉我说的不对的话,欢迎在评论区或者私聊指出,免得祸害其他读者。

再讲这两个服务的时候,我要先讲一个在本贴的概念:上下文

我相信,很多人都听过这个“上下文”,但是可能有点模糊,在我这里给大家解释解释看看大家接不接受这个说法。

还记得angular的数据绑定吗?比如:我现在有个有个叫TestCtrl的控制器,他的内容如下:

.controller('TestCtrl', function($scope) {
      $scope.test = "Boo!!!"
  })

而在html中我们的代码是这样的

<body ng-controller="TestCtrl">
  {{test}}
</body>

那么,大家不用想都知道结果了,页面上肯定会显示 Boo!!!的字样。

但是如果我删掉ng-controller的指令呢?也就是我没有在html申明控制器,你直接绑定{{test}}会如何呢?

结果只有一个,那就是页面啥都没有(ps:因为你申明了ng-app)。讲到这里大家明白了吗?

控制器就相当于一个上下文的容器,真正的上下文其实是$scope,当页面绑定test,如果申明了控制器,当前上下文就是控制器里面的$scope,ng会去找一下你这个控制器的上下文$scope有没有test,如果有,他当然就显示出来了,但是你不申明控制器的时候呢?他的上下文容器就是ng-app了,那么他真正的上下文就是$rootScope,这个时候他就会寻找$rootScope有没有test。

好了,上下文的概念已经讲完了,其实挺容易理解的,基本上和this非常相似

那么言归正传,我们开始讲$parse,首先我们要看的是ng的API文档

var getter = $parse('user.name');
var setter = getter.assign;
var context = {user:{name:'angular'}};
var locals = {user:{name:'local'}};

expect(getter(context)).toEqual('angular');
setter(context, 'newValue');
expect(context.user.name).toEqual('newValue');
expect(getter(context, locals)).toEqual('local');

大家看到的是ng文档里面对于$parse服务性价比最高的几行代码,

getter和setter就是大家所熟知的get方法和set方法了,context和locals仅仅是json对象而已,目的就是模拟上下文关系

大家看到的下面四个语句最终都能通过测试,现在我们一个个来分析,分析之前我要解释一遍什么叫$parse

$parse服务其实就是一种解析表达式的功能,就像ng-model=“test”,你在html中写这个东西谁知道你ng-model=“test”中,其实你想绑定的是当前控制器(上下文容器)中scope(上下文)中的test里面的值,ng就是通过$parse服务去帮助你解析这个表达式的,所以在调用$parse服务的时候你需要传递上下文对象,让ng知道你是要去哪里的scope(上下文)去找你这个test。

所以我们看到第一行测试代码是这样的:

getter(context)).toEqual('angular') //实际上就是 $parse('user.name')(context)

在这个context就是上下文,他能返回“angular“这个字符串的原理就是经过这三步的:

1.获取当前的表达式user.name

2.获取当前的上下文对象{user:{name:’angular’}}

3.在上下问对象中寻找表达式,最终获得“angular“这个字符创

所以这句测试代码是成功的。

我们看第二个方法setter方法

setter(context, 'newValue');//实际上就是 $parse('user.name').assign(context, 'newValue')
expect(context.user.name).toEqual('newValue');//测试数据上下文的值是否被改变

这里的setter方法其实是改变值得方法

1.获取当前的表达式user.name

2.获取当前的上下文对象{user:{name:’angular’}}

3.改变表达式中的值,将上下文对象编程{user:{name:’newValue’}}

于是上下文对象发生了改变,重新用getter方法去获取表达式的时候,上下文已经从{user:{name:’angular’}} –> {user:{name:’newValue’}},最后获取的表达式的值自然就是“newValue”了,所以测试代码也是通过的。

expect(getter(context, locals)).toEqual('local');//实际上就是$parse('user.name')(context, locals)

这里要表现的其实是上下文的替换功能。

在getter的方法中我们不仅可以选择第一个上下文,但是如果我们传递了第二个参数,那么第一个上下文就会被第二个上下文覆盖,注意是覆盖.

1.获取当前的表达式user.name

2.获取当前的上下文对象{user:{name:’angular’}}

3.覆盖当前的上下文{user:{name:’local’}}

4.获取解析之后表达式的值

重新回到$eval这个地方,我们看待$eval源码中可以看出$eval只有get功能,而没有set功能,但是有些时候我们可以选择传递第二个上下文,来达到修改值得效果。

在这里$parse服务就已将说完了,接下来就是$compile

————————————————–

如果你了解了$parse的概念之后,我想$compile也差不多理解了,其实和$parse很像。但是他是解析一段html代码的,他的功能就是将死模板变成活模板,也是指令的核心服务。

比如你有一段html代码 <h1>{{test}}</h1>,如果你将这段代码直接放在html代码里面,它所呈现的内容是怎样的我不说大家也应该懂。这就是死模板了,而所谓的活模板,就是这里面的数据全部经过了数据的绑定 {{test}}会自动找到当前的上下文,来绑定数据。最后显示出来的 就是活模板,也就是经过数据绑定的模板。

$compile(‘死模板’)(上下文对象),这样就将死模板编程了活模板,你就可以对这段活的html代码做操作了,例如增加到当前节点,等等。

但是在指令中,她会返回两个函数pre-link和post-link

第一个执行的是pre-link,它对于同一个指令的遍历顺序是从父节点到子节点的遍历,在这个阶段,dom节点还没有稳定下来,无法做一些绑定事件的操作,但是我们可以在这里进行一些初始化数据的处理。

第二个执行的是post-link,也就是我们常说的link函数,他是从子节点到父节点遍历的,在这个阶段,DOM节点已经稳定下来了,我们一般会在这里进行很多的操作。

以上就是小编为大家带来的基于angular中的重要指令详解($eval,$parse和$compile)全部内容了,希望大家多多支持脚本之家~

您可能感兴趣的文章:

  • angularjs指令中的compile与link函数详解
  • Angular中$compile源码分析
  • Angular的Bootstrap(引导)和Compiler(编译)机制
  • AngularJs html compiler详解及示例代码
  • 浅谈Angularjs link和compile的使用区别
  • angular.js指令中的controller、compile与link函数的不同之处
张贴在3