这里是修真院前端小课堂,每篇分享文从
八个方面深度解析前端知识/技能,本篇分享的是:
【angular之中,$state $watch $scope $rootScope 分别是什么? 】
1.背景介绍
AngularJs是一个用于设计动态web应用的结构框架,使得开发现代的单一页面应用程序变得更加容易。而且能够简化我们的工作流程, 让我们只专心于业务逻辑和数据的处理。$scope $rootScope $watch 和 $state就是里面的几个方法。
2.知识剖析
1、 s c o p e — — S c o p e ( 作 用 域 ) 是 应 用 在 H T M L ( 视 图 ) 和 J a v a S c r i p t ( 控 制 器 ) 之 间 的 纽 带 。 S c o p e 是 一 个 对 象 , 有 可 用 的 方 法 和 属 性 。 S c o p e 可 应 用 在 视 图 和 控 制 器 上 。 scope——Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带。Scope 是一个对象,有可用的方法和属性。 Scope 可应用在视图和控制器上。 scope——Scope(作用域)是应用在HTML(视图)和JavaScript(控制器)之间的纽带。Scope是一个对象,有可用的方法和属性。Scope可应用在视图和控制器上。scope 的使用贯穿整个 Angular App 应用,它与数据模型相关联,同时也是表达式执行的上下文。 有了 $scope 就在视图和控制器之间建立了一个通道,基于作用域视图在修改数据时会立刻更新 $scope, 同样的 $scope发生改变时也会立刻重新渲染视图。
2、$rootscope——每一个Angular应用都会有一个 $rootScope。这个 $rootScope 是最顶级的scope,它对应着含有 ng-app 指令属性的那个DOM元素。 如果页面上没有明确设定 $scope ,Angular 就会把数据和函数都绑定到这里。Angular 应用启动并生成视图时,会将根 ng-app 元素与 r o o t S c o p e 进 行 绑 定 . rootScope 进行绑定. rootScope进行绑定.rootScope 是所有 $scope 的最上层对象, 可以理解为一个 Angular 应用中得全局作用域对象。
3、$scope 的生命周期有4个阶段:
(1)创建:控制器或者指令创建时, Angular 会使用 $injector 创建一个新的作用域,然后在控制器或指令运行时,将作用域传递进去。
(2)链接:Angular 启动后会将所有 $scope 对象附加或者说链接到视图上,所有创建 $scope 对象的函数也会被附加到视图上。 这些作用域将会注册当 Angular 上下文发生变化时需要运行的函数.也就是 $watch 函数, Angular 通过这些函数或者何时开始事件循环。
(3)更新:一旦事件循环开始运行,就会开始执行自己的脏值检测.一旦检测到变化,就会触发 $scope 上指定的回调函数。
(4)销毁:通常来讲如果一个 $scope 在视图中不再需要, 需要对其进行清理。
4、 w a t c h — — 相 信 使 用 过 a n g u l a r j s 的 同 学 都 知 道 , n g 中 有 个 比 较 重 要 的 特 点 , 叫 做 双 向 绑 定 , 那 么 这 个 双 向 绑 定 是 如 何 实 现 的 呢 ? 当 我 们 在 对 绑 定 的 n a m e 属 性 进 行 修 改 的 时 候 , a n g u l a r 内 部 的 watch——相信使用过angularjs的同学都知道,ng中有个比较重要的特点,叫做双向绑定,那么这个双向绑定是如何实现的呢? 当我们在对绑定的name属性进行修改的时候,angular内部的 watch——相信使用过angularjs的同学都知道,ng中有个比较重要的特点,叫做双向绑定,那么这个双向绑定是如何实现的呢?当我们在对绑定的name属性进行修改的时候,angular内部的digest循环级会执行一次, 他执行的内容是检查我们的 s c o p e 作 用 域 的 内 容 与 上 次 执 行 scope作用域的内容与上次执行 scope作用域的内容与上次执行digest循环的时候是否有变化,若有变化就执行$watch()方法绑定的处理函数。 从而 达到了监听作用域属性的效果。
5、$watch(watchExpression, listener, objectEquality);
watchExpression,需要监控的表达式;
listener,处理函数,函数参数如下 function(newValue,oldValue, scope);
objectEquality,是否深度监听,如果设置为true,它告诉Angular检查所监控的对象中每一个属性的变化. 如果你希望监控数组的个别元素或者对象的属性而不是一个普通的值, 那么你应该使用它。
6、 s t a t e — — 在 a j a x 技 术 发 展 普 及 之 后 , 因 为 其 不 会 留 下 历 史 记 录 方 便 浏 览 器 访 问 和 对 于 s e o 不 友 好 的 特 点 , 一 个 新 技 术 应 运 而 生 : 路 由 , state——在ajax技术发展普及之后,因为其不会留下历史记录方便浏览器访问和对于seo不友好的特点,一个新技术应运而生: 路由, state——在ajax技术发展普及之后,因为其不会留下历史记录方便浏览器访问和对于seo不友好的特点,一个新技术应运而生:路由,state就是路由中的一项服务。
7、 s t a t e . g o ( ) — — state.go()—— state.go()——state.go()方法可以产生与a链接一样的效果,可以将此方法绑定给一个button按钮, 然后在按钮的点击事件中执行 $state.go(),就可以跳转到相应的页面。
8、 s t a t e p a r a m s — — stateparams—— stateparams——stateParams是一个对象,包含 url 中每个参数的键/值。 s t a t e P a r a m s 可 以 为 控 制 器 或 者 服 务 提 供 u r l 的 各 个 部 分 。 注 意 : stateParams可以为控制器或者服务提供 url 的各个部分。 注意: stateParams可以为控制器或者服务提供url的各个部分。注意:stateParams必须与一个控制器相关,并且$stateParams中的“键/值”也必须事先在那个控制器的url属性中有定义。
3.常见问题
watch的深度监听是什么意思呢?有什么优缺点呢?
4.解决方案
w a t c h 在 对 待 原 始 类 型 和 引 用 类 型 会 有 不 同 的 处 理 方 式 , 这 就 要 首 先 说 一 说 watch在对待原始类型和引用类型会有不同的处理方式,这就要首先说一说 watch在对待原始类型和引用类型会有不同的处理方式,这就要首先说一说watch函数的第三个参数。在前面的例子中, 我们知道, w a t c h 函 数 有 接 收 两 个 参 数 , 第 一 个 参 数 是 需 要 监 视 的 对 象 , 第 二 个 参 数 是 在 监 视 对 象 发 生 变 化 时 需 要 调 用 的 函 数 , 实 际 上 watch函数有接收两个参数,第一个参数是需要监视的对象,第二个参数是在监视对象发生变化时需要调用的函数, 实际上 watch函数有接收两个参数,第一个参数是需要监视的对象,第二个参数是在监视对象发生变化时需要调用的函数,实际上watch还有第三个参数,它在默认情况下是false。在默认情况下,即不显式指明第三个参数或者将其指明为false时, 我们进行的监视叫做“引用监视”。引用监视的原词的“reference watch”,它的意思是只要监视的对象引用没有发生变化, 就不算它发生了变化。如果我们将 w a t c h 的 第 三 个 变 量 设 置 为 t r u e , 那 么 此 时 我 们 进 行 的 监 视 叫 做 “ 全 等 监 视 ” , 原 词 是 “ e q u a l i t y w a t c h ” 。 此 时 , 只 要 watch的第三个变量设置为true,那么此时我们进行的监视叫做“全等监视”,原词是“equality watch”。 此时,只要 watch的第三个变量设置为true,那么此时我们进行的监视叫做“全等监视”,原词是“equalitywatch”。此时,只要watch的对象有一点风吹草动,它马上就跳出来 既然全等监视这么好,那么我们为什么不直接用全等监视呢?当然,任何事情都有好的坏的两个方面,全等监视固然是好, 但是它在运行时需要先遍历整个监视对象,然后在每次$digest之前使用angular.copy()将整个对象深拷贝一遍然后在运行之后用angular.equal()将前后的对象进行对比。
5.编码实战
6.扩展思考
ui-sref、$state.go 的区别?
(1)ui-sref 一般使用在 …,
例如:message。
(2)$state.go(‘someState’)一般使用在 controller里面,
例如:.controller(‘firstCtrl’, function($scope, $state) {
$state.go('login');
});
(3)这两者的本质上是一样的,从ui-sref的源码可以看出ui-sref最后调用的还是$state.go()方法。
7.参考文献
参考一:http://yuankeqiang.lofter.com/post/8de51_1454f93;
参考二:https://blog.csdn.net/u010451286/article/details/50635839;
参考三:http://angular-tips.com/blog/2013/08/watch-how-the-apply-runs-a-digest/;
参考四:https://www.jb51.net/article/80492.html;
参考五:https://www.cnblogs.com/koleyang/p/4576419.html
8.更多讨论
问题一:$stateParams如果没有用url接收会怎样?
答:如果没有在url里面接收,会导致再次提取 s t a t e P a r a m s 中 的 数 据 的 时 候 , 会 找 不 到 该 数 据 ; stateParams中的数据的时候,会找不到该数据; stateParams中的数据的时候,会找不到该数据;stateParams对象中根本就没有该属性。
问题二: $watch脏检测原理是什么?
答:scope通过$watch方法向this.
watchers数组中添加watcher对象(包含watchFn,listenerFn,valueEq,last四个属性)。每当$digest循环被触发时,它会遍历
watchers数组,执行watcher中的watchFn,获取当前scope上某属性的值(一个watcher对应scope上一个被监听属性),然后去同watcher中的last(上一次的值)做比较,若两值不相等,就执行listenerFn。
问题三: r o o t S c o p e 是 否 可 以 替 代 rootScope是否可以替代 rootScope是否可以替代scope?
答:可以,但是不建议这样用,相当于js中的全局变量,定义过多会导致全局污染。