利用$scope暴露模型数据

利用向控制器传递$scope对象的机制,可以把模型数据暴露给试图。在你的应用中可能还有其他数据,但是只有通过$scope 触及这些数据,angular才会把它当成数据模型的一部分。你可以把$scope当成一个上下文环境,它让数据模型上的变化变得可以观察。对于显式地创建$scope属性,例如:$scope.count = 5;还可以间接的通过模板自身创建数据模型。我们可以通过以下几种方式来实现这一点:

1:通过表达式。既然表达式是在控制器的$scope环境中执行的,而这个$scope与它们所管理的元素有关,那么在表达式中设置属性值就和设置控制器的$scope属性值是一样的。即:

<button on-click=”count = 3”>click me</button>

与下面的这种做法的效果是相同的:

<div ng-controller = ‘count’>

<button ng-click=’set()’>click me</button>

</div>

Controller 定义如下:

Function count ($scope) {

$scope.set = function(){

$scope.count = 3;

}

}

2:在表单项上使用ng-model。与表达式类似,ng-model上指定的模型参数同样工作在外层控制器内,唯一不同的在于:这样会在表单项和指定的模型之间建立双向绑定的关系。

使用$watch监控数据模型的变化

在$scope内置的所有函数中,用的最多的可能就是$watch函数了。当你的数据模型中某一部分发生变化时,$watch函数可以向你发出通知。你可以监视单个对象的属性,也可以监控需要经过计算的结果,实际上只要能够被当做属性访问到,或者可以当作一个js函数计算出来,就可以被$watch函数监控。它的函数签名为:       $watch( watchFn , watchAction , deepWatch )

其中每个参数的详细含义如下:

watchFn:该参数是一个带有angular表达式或者函数的字符串,它会返回被监控的数据模型的当前值。这个表达式将会被执行多次,所以你要保证它不会产生其他副作用。也就是说:要保证它可以被调用很多次而不会改变状态。基于同样的原因,监控表达式应该很容易比计算出来。如果你使用字符串传递了一个angular表达式,那么它将会针对调用它的那个作用域中的对象而执行。

watchAction:这是一个函数或者表达式,当watchFn发生变化时会被调用,如果是函数的形式,它将会接收到watchFn的新旧2个值,以及作用域对象的引用。其函数签名是:function(newValue,oldValue,scope).

deepWatch:如果设置为true,这个可选的布尔型参数将会命令angular去检查被监控对象的每个属性是否发生了变化。如果你想要监控数组中的元素,或者对象上的所有属性,而不只是监控一个简单的值,你就可以使用这个参数。由于angular需要遍历数组或者对象,如果集合比较大,那么运算负担就会比较重。

$watch函数会返回一个函数,当你不再需要接收变更通知时,可以用这个返回的函数注销监控器。

如果我们需要监控一个属性,然后接着注销监控,我们可以使用以下的代码:

var dereg = $scope.$watch(‘some’,call());       dereg();

接下来我们将使用一个购物车的例子来使用$watch

  1. <!DOCTYPE html>
  2. <html ng-app="myApp">
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title>购物车演示</title>
  6. <script src="angular-1.4.2/angular.js" type="text/javascript"></script>
  7. </head>
  8. <body ng-controller="shopCartCtrl">
  9. <h1>Your Order</h1>
  10. <div ng-repeat="item in items">
  11. <span>{{ item.title }}</span>
  12. <input ng-model="item.quantity">
  13. <span>{{ item.price | currency }}</span>
  14. <span>{{ item.price * item.quantity | currency }}</span>
  15. </div>
  16. <div>total : {{ totalCart() | currency }}</div>
  17. <div>discount : {{ bill.discount | currency }}</div>
  18. <div>subtotal : {{ subtotal() | currency }}</div>
  19. <script>
  20. angular.module('myApp',[]).controller('shopCartCtrl', function ($scope) {
  21. $scope.bill = {};
  22. $scope.items = [
  23. {title : '111',quantity : 5,price : 3},
  24. {title : '222',quantity : 6,price : 8},
  25. {title : '333',quantity : 7,price : 13}
  26. ];
  27. $scope.totalCart = function(){
  28. var total = 0;
  29. for ( var i= 0 , len = $scope.items.length ; i < len ; i ++ ) {
  30. total = total + $scope.items[i].price * $scope.items[i].quantity;
  31. }
  32. return total;
  33. };
  34. $scope.subtotal = function () {
  35. return $scope.totalCart() - $scope.bill.discount;
  36. }
  37.  
  38. function calcul (newValue,oldValue,scope) {
  39. $scope.bill.discount = newValue > 100 ? 10 : 0;
  40. }
  41. $scope.$watch( $scope.totalCart,calcul);
  42. })
  43. </script>
  44. </body>
  45. </html>

我们在totalCart()的值上面设置了一个监控,用来计算此次购物的总价。只要这个值发生变化,监控器就会调用calcul(),然后我们就可以把折扣设置为相应的值。如果总价超过100美元,我们将会把折扣设置为10美元,否则,折扣为0.

这个是我们运行代码后看到的运行界面:

$watch()中性能注意事项

上面的例子可以正确的运行,但是却存在潜在的性能问题。如果你在totalCart()中打一个调试断点,你就会发现在渲染这个页面时,该函数被调用了6次。虽然在当前这个应用中它所引起的性能问题并不明显,但是在更加复杂的应用中,运行6次就会成为一个问题。

为什么是6次呢?其中3次我们可以很容易跟踪到,因为在以下每种情况下它都会运行一次:

1.  模板{{ totalCart() | currency }}

2.  Subtotal()函数

3.   $watch()函数

然后angular把以上真个过程又重复了一遍,最终就是6次。Angular的做法是:把所有被监控的属性都拷贝一份,然后把它们和当前的值进行比较,看看是否发生了变化。

解决方法:监控items数组的变化,然后重新计算$scope属性中的总价,折扣,和小计值。

为了实现这一点,我们需要把模板修改一下以便使用这些属性:

  1. <div>total : {{ bill.total | currency }}</div>
  2. <div>discount : {{ bill.discount | currency }}</div>
  3. <div>subtotal : {{ bill.subtotal | currency }}</div>

然后我们在js中,我们将会监控items数组,当数组发生任何变化时调用一个函数来计算总价:

  1. angular.module('myApp',[]).controller('shopCartCtrl', function ($scope) {
  2. $scope.bill = {};
  3. $scope.items = [
  4. {title : '111',quantity : 5,price : 3},
  5. {title : '222',quantity : 6,price : 8},
  6. {title : '333',quantity : 7,price : 13}
  7. ];
  8. $scope.totalCart = function(){
  9. var total = 0;
  10. for ( var i= 0 , len = $scope.items.length ; i < len ; i ++ ) {
  11. total = total + $scope.items[i].price * $scope.items[i].quantity;
  12. }
  13. $scope.bill.totalCart = total;
  14. $scope.bill.discount = total > 100 ? 10 : 0;
  15. $scope.bill.subtotal = total - $scope.bill.discount;
  16. };
  17. $scope.$watch( 'items',calcul,true);
  18.  
  19. })

监控多个东西:

如果你想监控多个属性或者对象,并且当其中任何一个发生变化时就去执行一个函数,有2中基本的选择:

1.  监控把这些属性连接起来之后的值

2.  把它们放到一个数组或者对象中,然后给deepWatch参数传递一个true值。

在第一种情况下,如果在你的作用域张存在一个things对象,它带有2个属性a和b,当这2个属性发生变化时都需要执行callMe()函数,你可以同时监控这2个属性,实列如下:

$scope.$watch(‘things.a + things.b’,callMe());

当然a和b也可以属于不同的对象,只要需要,这个列表可以无限长,如果列表非常长,你就需要写一个函数来返回连接后的值,而不是依赖一个表达式来完成这一逻辑。

在第二种情况下,你需要监控things对象上的所有属性,你可以这样做:

$scope.$watch(‘things’,callMe(),true);

这里,给第三个函数传递了一个true,请求angular遍历things的属性,然后当其中任何一个属性发生变化时就调用callMe().这一机制在数组上的运行方式和对象上的运行方式相同。

AngularJs 第三节随笔的更多相关文章

  1. AngularJs的$http使用随笔

    AngularJs的$http服务是Angularjs自带的核心服务之一,用来与HTTP远程服务器交互. 关于$http使用,我体会的一下几点注意: 1.在使用是报“Uncaught Referenc ...

  2. AngularJS 学习随笔(一)

    AngularJS 初始化加载流程: 1:浏览器载入HTML,然后把它解析成DOM 2:浏览器载入Angular.JS 脚本 3:AngularJS 等到DOMContentLoaded时间触发 4: ...

  3. AngularJS(1)随笔

    ng-app 指令告诉 AngularJS,<div> 元素是 AngularJS 应用程序 的"所有者". ng-model 指令把输入域的值绑定到应用程序变量 na ...

  4. angularJS随笔

    1.作用域 基于作用域的事件传播 作用域可以像DOM节点一样,进行事件的传播.主要是有两个方法: broadcasted :从父级作用域广播至子级 scope emitted :从子级作用域往上发射到 ...

  5. 随笔编号-04 AngularJS 相关小问题解决方案合集

    1  解决 Select选择框遍历时,出现一个空白选项: <select style="width: 20%;margin-left: 5px;height: 31px;" ...

  6. AngularJS 系列 01 - HelloWorld和数据绑定

    目录导读: AngularJS 系列 学习笔记 目录篇 前言: 好记性不如烂键盘,随笔就是随手笔记,希望以后有用. 本篇目录: 1. Hello World 2. AngularJS中的数据绑定 3. ...

  7. AngularJS笔记---路由视图

    最近有同事提到过关于ng-view的使用, 其实自己也不懂了,由于最近一直在做AngularJs的Rearch,所以就看了一些关于ng-view的国外博客. 做过ASP.NET MVC4的都知道, 我 ...

  8. angularjs指令系统系列课程(1):目录

    angularjs里面有一套十分强大的指令系统 比如内置指令:ng-app,ng-model,ng-repeat,ng-init,ng-bind等等 从现在开始我们讲解AngularJS自定义指令, ...

  9. requirejs按需加载angularjs文件

    之前分享了一篇用ocLazyLoad实现按需加载angular js文件的博客.本来当时想会使用一种方法就行了.可最近刚好有时间,在网上查找了一下requirejs实现angular js文件按需加载 ...

随机推荐

  1. 从网络通信角度谈web性能优化

    衡量一个网站的性能有多个指标,DNS解析时间,TCP链接时间,HTTP重定向时间,等待服务器响应时间等等,从用户角度来看,就可以归结为该网站访问速度的快慢.也就是说性能等于网站的访问速度. 早些年Am ...

  2. 仿QQ空间动态界面分享

    先看看效果: 用极少的代码实现了 动态详情 及 二级评论 的 数据获取与处理 和 UI显示与交互,并且高解耦.高复用.高灵活. 动态列表界面MomentListFragment支持 下拉刷新与上拉加载 ...

  3. vscode同步设置&扩展插件

    首先安装同步插件: Settings Sync 第二部进入你的github如图:  打开设置选项: 新建一个token: 如图:  记住这个token值 转到vscode 按shift+alt +u ...

  4. iOS 相册和网络图片的存取

    iOS 相册和网络图片的存取 保存 UIImage 到相册 UIKit UIKit 中一个古老的方法,Objective-C 的形式 void UIImageWriteToSavedPhotosAlb ...

  5. sdkman安装

    软件开发工具管理包(Software Development Kit Manager,简称SDKMAN) 用来管理多个版本的开发环境的工具.提供命令行来安装.切换.删除.列出候选版本. 官网地址:ht ...

  6. 原生JS和JQuery代码编写窗口捕捉函数和页面视觉差效果(scroll()、offsetTop、滚动监听的妙用)

    想实现窗口滚动到一定位置时,部分网页的页面发生一些变化,但是手头没有合适的插件,所以就想到自己编写一个简易的方法, 想到这个方法要有很高的自由度和适应性,在这,就尽量的削减其功能,若有错误的地方或者更 ...

  7. Net分布式系统之五:微服务架构

    因工作较忙,抽时间将框架遇到的问题和框架升级设计进行记录. 一.背景&问题 之前框架是一个基于SOA思想设计的分布式框架.各应用通过服务方式提供使用,服务之间通信是RPC方式调用,具体实现基于 ...

  8. 关于在"a"标签中添加点击事件的一些问题

    昨天做修改页面跳转时遇到一个问题,如果a标签的"href"属性为空的话,比如这样<a href="" onclick="roleupdate() ...

  9. 1013 Realtime Status

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...

  10. node中创建服务进程

    背景 在node工程部署中,常常涉及到三方:本地客户端.跳板机和服务器(集群).在通过git触发gitlab hook脚本后,需要在跳板机中执行相应的ssh命令执行shell文件启动node服务器,这 ...