文档章节

学习 AngularJS (五) scope

刘军兴
 刘军兴
发布于 2015/12/09 14:53
字数 1588
阅读 102
收藏 1

继续看 kityminder-editor 部分代码, 一层层进入到 undoRedo.directive.js, 以及对应的模板文件 undoRedo.html,
又看不懂里面的 angularjs 相关代码了, 怎么办?? --- 只能是回学校重新学啊.

幸好买的书到了, 《精通AngularJS》. 但为了弄懂 kityminder 就得学这么多东西, 是不是很复杂? 
万一以后领导/客户说还要改点什么, 一定会更复杂吧...?

将粗看一下部分开始章节, 期望重点了解 scope, directive 概念.

AngularJS 的 MVC 模式

MVC 太知名了, 招聘时年轻的学子们有问你们用不用 MVC 模式, 我都不知道该怎么回答. 看他们表情仿佛是若不用 MVC,
就很落伍很低级 -> 不来. 所以, 还是赶紧学一下什么是 MVC 吧!

MVC (model-view-controller), 是一种架构(architect)模式, 相当抽象. 当前有很多变种和派生 (如 MVP,
MVVM 模式), 开发者有自己对 MVC 的理解并有不同的设计架构. 导致同样的 MVC 名字有不同的架构...

AngularJS 采用注重实效的方式 -> MVW(model-view-whatever) 模式.

书上例子: hello-world 使用 ng-controller:

<div ng-controller='HelloCtrl'>
  <h1>Hello, {{name}}!</h1>
</div>

<script>
function HelloCtrl($scope) {
  $scope.name = 'angular';
}
</script>

要亲自实验一下才放心, 于是写简单网页吧, 看看到底能行不? --- 测试结果: 没通过...

换一下写法, 下面这种才能通过:

<div ng-app='demo' ng-controller='HelloCtrl'>
  <h1>Hello {{ name }}!</h1>
</div>

<script>
angular.module('demo', []) // 必须有一个 module 吗?
  .controller('HelloCtrl', ['$scope', function($scope) { // 必须注册到 module 吗?
    console.log('HelloCtrl() is called, $scope is: ', $scope);
    $scope.name = 'World';
  }]);
</script>

(这样, 看这书是不是前景堪忧啊...) 还是先继续看 scope (作用域)概念吧.

 

作用域 (scope)

AngularJS 中的 $scope 对象是模板的域模型(domain model), 也称为作用域实例 (instance).
通过为其属性赋值, 可以传递数据给模板渲染.

上面的 HelloCtrl 例子中, 输出的 $scope 如下图样子:

 

初看应是一个 Scope 类的实例, 以 $$, $ 开头的属性和方法应该是 angularjs 内部使用的. name 属性是我们添加的.
还注意到有 $id, $parent, $root 属性, 应是构成了 scope 的树结构(层次结构).

书上写向 scope 赋值, 可以传递数据给模板渲染, 那我们来做实验, 手动在 console 中输入语句为 $scope.name 赋新值,
看看能发生什么...?  --- 答案是: 没变化. 这意味着什么?

既然 $scope 对象是模板 (对应 view 吗?) 的域模型 (对应 model 吗?), ... 那么就有了 M&V of MVC 了吗?

作用域 (scope) 可以加入与模板相关的数据(data)和提供相关的功能(function). 例子, 用函数 getName() 替代
name 属性 (实验通过):

angular... .controller(..., function($scope) {
  $scope.getName = function() {
    return 'World';
  }
});
// 对应模板写作: Hello, {{ getName() }}

证明了啥? 证明 AngularJS expression 能支持调用 $scope 上的函数......

$scope 对象可以精准地控制领域模型 (domain model) 的哪些数据和操作在视图上 (view) 上是有效的.
概念上来说, AngularJS 的作用域 (scopes) 与 MVVM 模式的视图模型 (view-model) 非常相似.

控制器

控制器(controller) 的主要职责是初始化作用域 (scope) 实例 (instance).

可以 1. 属性 在 $scope; 2. 方法 于 $scope, 一般是 UI 相关的行为. 

在初始化 scope instance (View-Model of MVVM) 时, controller 与 ng-init 可以做同样的工作.

实验: 我们即有 ng-init 又有 controller, 会发生什么?

<div ng-controller='HelloCtrl' ng-init='name = "Warlord"' >
  Hello {{ name }}!
</div>
// controller 部分中设置 $scope.name = 'World', 其它不变.

结果显示 Hello Warlord! 这说明了什么?

既然 controller 能用, 则尽量将代码放到 controller 中, 而不是将 js 混在 html 模板中.
书上说控制器就是一个 js 函数, 不需要扩展任何 angularjs 特定的类, 不需要调用特定 angularjs api ...
但我单独写 controller 函数却无法通过实验, 也许我还不太熟悉 angular, 又或者旧版本可以写函数?

模型

AngularJS 的模型 (model) 实际上就是普通的 js 对象. 不需要去扩展任何 angularjs 底层类.

可以使用任何 js 类或对象, 属性也不仅限于原始值 (primitive values).

AngularJS 没有侵略性, 它让模型对象远离框架特定的代码. (请一下此设计)

深入作用域

每个 $scope 都是 Scope 类的实例. (我们上面观察 $scope 对象时可注意到这一点)

作用域层级

问题: controller 函数的参数 $scope 从何而来?
答案是: ng-controller 指令使用 scope 对象的 $new(isolate, parent) 方法创建新的作用域, 传递给 controller 函数.
   angularjs 在新应用启动时自动创建 $rootScope 作为其他所有 scope 的父 scope. (?是否 ng-app 启动一个新应用)

ng-controller 指令是作用域创建 (scope-creating) 指令. 每当 DOM 树中遇到此类指令, 都会创建 Scope 类的
新实例 $scope. 新的 $scope 拥有 $parent 属性, 指向它的父作用域.

由于 DOM 是树结构, 附加在 DOM 上的创建 scope 的指令创建出 scope 树也是不奇怪的.

如重复器(repeater)指令 ng-repeat 会创建子作用域, 看例子:

<div ng-controller='HelloCtrl'>
  <ul>
    <li ng-repeat='i in [2,3,5,7]'>Number is {{ i }}</li>
  </ul>
</div>

页面显示出 2,3,5,7 在一个 ul 中. 查看 html 发现有多个 DOM 元素 class 中含有 ng-scope:

 

按照书上指引, 找到一个 Firefox 的扩展 AngScope - AngularJS 作用域查看器 for Firebug, 在 DOM 元素上右键
点击, 出现菜单 'Inspect Angular Scope', 然后可以查看该元素所属作用域. (启发: 也许还有别的 angular 插件...)
(Chrome 类似扩展为 Batarang)

经过查看会发现一些惊人的事实, body 上的 scope.$id = 1, .parent = null, 这应该是为 demo ng-app 创建的根
作用域. div HelloCtrl ng-controller 的 scope.$id = 2, .parent = scope#1;
每个被重复的 li 都有自己的 scope, $id 对应为 3,4,5,6, 其 .parent = scope#2.
也即每个 li 都创建了一个新的 scope...

而且这些 scope 的 __proto__ 属性也比较怪, 似乎就是其 $parent 的值, 也是一层一层向上直到 null.
这种技术似乎很少看到. 也许我应该多花点时间看看其它 js 库? (可是还有事情要忙, 没时间怎么办?) 

用 Chrome + 扩展 Batarang 查看似乎更方便:

 

从而这里就能明白, 为什么在一个 repeater 里面可以访问到 $index, $first, $last, $even, $odd 等属性的原因了.

(休息一下, 下篇接着学...)

© 著作权归作者所有

共有 人打赏支持
刘军兴
粉丝 54
博文 184
码字总数 226359
作品 0
昌平
AngularJs学习笔记--expression

一、Angular表达式 vs. Js 表达式   这很容易让人将angular视图表达式联想为javascript表达式,但这并不完全正确,因为angular不是通过javascript的eval()对表达式进行求值。你可以将angul...

武文海
2015/02/06
0
0
Angular.js 相关记录

AngularJS作用域文档:http://docs.angularjs.org/api/ng.$rootScope.Scope ng-view 指令的角色是为当前路由把对应的视图模板载入到布局模板中。 AngularJS内置过滤器:http://code.angular...

彭博
2014/04/25
0
2
angular js 自学笔记(一)

js中的mvc mvc设计模式,简单说来是将复杂的代码设计规范化,把应用的输入,处理,输出分开,M是指数据模型,V是指用户界面,C则是控制器。像我刚接触的SSH框架中,例如struts,就是利用mvc的...

烽穹寒渊
2015/03/09
0
0
AngularJS - Top 6 Concepts that Developers Loved

This article represents top 6 popular AngularJS topics that has been used most by the AngularJS developer community to date. The inference is derived based on number of tagged d......

perfectspr
2014/12/03
0
0
探索angular源码--启动(1)

前言 angular2.0已经出来了,本来应该是研究最新的angular源码,但毕竟用了angular1这么久了,一直对其源码实现十分好奇,再加上研究源码主要目的是学习,版本不是特别重要,因此就1.3版源码...

烽穹寒渊
2015/08/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

《Netkiller Java 手札》· 二进制文件操作大全

本文节选自《Netkiller Java 手札》 Netkiller Java 手札 Mr. Neo Chan, 陈景峯(BG7NYT) 中国广东省深圳市望海路半岛城邦三期 518067 +86 13113668890 <netkiller@msn.com> $Id: book.xml 6......

netkiller-
15分钟前
0
0
Fiddler Debugger post请求

常用的两种: 第一种默认的 对应URL为www 的要用请求头为:Content-Type: application/x-www-form-urlencoded 请求参数为 :param1=1234¶m2=12345 注:有些接口是指定用这种的第二方式并不...

轻量级赤影
22分钟前
1
0
如何搭建母婴亲子类知识社区

近期社交领域融资动作频繁,海尔高管、海尔医疗有限公司总裁管礼庆创办的母婴知识分享社区平台Alwayslove于上月获得700万天使轮融资。 Alwayslove是一个母婴知识分享社区平台,采用UGC模式,...

ThinkSNS账号
24分钟前
0
0
Android 自定义构建类型 BuildType

最近接触到自定义构建类型 BuildType,发现这一块有些地方稍不注意的话会被绕进去浪费点时间,既然我这边已经花费时间了,如果正好你也需要接触到 BuildType,也许接下来分享的 tips 可能会帮...

猴亮屏
25分钟前
1
0
美团点评基于 Flink 的实时数仓建设实践

引言 近些年,企业对数据服务实时化服务的需求日益增多。本文整理了常见实时数据组件的性能特点和适用场景,介绍了美团如何通过 Flink 引擎构建实时数据仓库,从而提供高效、稳健的实时数据服...

美团技术团队
29分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部