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中我们的代码是这样的
<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)的更多相关文章
- angular源码分析:angular中脏活累活承担者之$parse
我们在上一期中讲 $rootscope时,看到$rootscope是依赖$prase,其实不止是$rootscope,翻看angular的源码随便翻翻就可以发现很多地方是依赖于$parse的.而$pa ...
- Angular中ngCookies模块介绍
1.Cookie介绍 Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie.内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短 ...
- angular中ng-bind指令小案例
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- angular源码分析:angular中入境检察官$sce
一.ng-bing-html指令问题 需求:我需要将一个变量$scope.x = '<a href="http://www.cnblogs.com/web2-developer/&qu ...
- angular源码分析:angular中$rootscope的实现——scope的一生
在angular中,$scope是一个关键的服务,可以被注入到controller中,注入其他服务却只能是$rootscope.scope是一个概念,是一个类,而$rootscope和被注入到cont ...
- angular中transclude的理解
今天被这个transclude搞糊涂了,弄了半天,才知道原来使用起来很简单.很烦恼为社么书中的对于这个的介绍这么晦涩难懂.直到看到了这篇文章,才让我弄清楚了. 一.transclude介绍 trans ...
- Angular中的数据绑定
(1)HTML绑定:{{}} (2)属性绑定:[] 注意:属性绑定通常赋值为变量,如果赋值为常量(如字符串常量) 必须用引号括起来,如<img [src]="'../../assets ...
- 【转】angular中$parse详解教程
原文: https://yq.aliyun.com/ziliao/40516 ------------------------------------------------------------- ...
- Angular中的内置指令和自定义指令
NG中的指令,到底是什么(what)? 为什么会有(why)?以及怎样使用(how)? What: 在NG中,指令扩展HTML功能,为 DOM 元素调用方法.定义行为绑定数据等. Why: 最大程度减 ...
随机推荐
- DrawerLayout,ToolBar 和 TabHost 的使用
ActionBar 定义起来不方便 toolbar: 最重要的特性,显示menu菜单,右上角三个点的菜单按钮,使用灵活 使用:1,布局文件,包裹LinearLayout 放imageView, 或者I ...
- vultr vps新增reserved IPs功能,保留服务器原有IP
高性价比海外vps品牌vultr vps宣布一项新功能叫“reserved IPs”,顾名思义是帮助你保留服务器IP地址,以备后用. 这个需求是因为用户经常新建.删除一个vps服务器,默认分配的是随机 ...
- C# 中获取时区列表
c#中获取时区列表 下面方法获得的仅仅用来显示和使用,无法用来进行时间转换. public static List<DisplayTimeZone> GetSystemTimeZones( ...
- javsscript总结
- ABP组件包升级
对于abp的爱好者来说在使用abp上会面临两个问题,第一个是如何上手,第二是如何升级,然而们今天的主题是如何升级abp的组件包.目前我项目版本是0.8.2 通过官网boilerplate生成的项目前端 ...
- Dynamics CRM 相关资料
links: 1.The Microsoft Dynamics CRM Team Blog 2.申请试用Dynamics CRM 2013 http://www.microsoft.com/zh-cn ...
- HDOJ-1051 Wooden sticks(贪心)
Wooden Sticks Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tot ...
- js检测对象中是否存在某个属性
1.使用in关键字.该方法可以判断对象的自有属性和继承来的属性是否存在. 2.使用对象的hasOwnProperty()方法.该方法只能判断自有属性是否存在,对于继承属性会返回false. 3.用un ...
- curl的简单使用步骤
要使用cURL来发送url请求,具体步骤大体分为以下四步: 1.初始化2.设置请求选项3.执行一个cURL会话并且获取相关回复4.释放cURL句柄,关闭一个cURL会话 // 1. 初始化一个cURL ...
- HDU 5908 Abelian Period (BestCoder Round #88 模拟+暴力)
HDU 5908 Abelian Period (BestCoder Round #88 模拟+暴力) 题目链接http://acm.hdu.edu.cn/showproblem.php?pid=59 ...