New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

看AngularJS文档需要注意的一些关键点 #7

Open
ericdum opened this Issue Dec 14, 2013 · 1 comment

Comments

Projects
None yet
2 participants
@ericdum
Owner

ericdum commented Dec 14, 2013

看AngularJS文档需要注意的一些关键点

我们这些英语不好的人,看英文文档最容易忽略的就是大段大段的文字。转而去看示例代码和代码解释,更有甚者是直接去看API文档、看源码。但是这样要把一个框架的结构和使用方式看懂是很有难度的,就像盲人摸像,如果不把整个大象全身摸完,是无法正确理解这头象的。

同时“没有万能的东西”这句话也能用在框架上,任何一个东西都有他特定的应用场景和思路。所以选择并使用一个东西的时候一定要关注作者的设计思路是不是和你预期的一致,也就是,你是不是作者的典型用户。如果是,这个优秀的框架一定能把你服务得很好;如果不是,换一个,或者试着改变自己的思路。

Angular尤其是一个颠覆传统web应用开发模式的框架,所以尤其需要关注,甚至是直接学习他的思路。

这篇文章就是把Developer Guide中的部分我觉得重要的信息摘选出来翻译。大多都不包含代码和具体用法,因为那些实例我们都很熟。

概念

Conceptual Overview

这是在创建第一个app之前就应该理解的Angular的概念。

概念 定义
Template 使用了额外标记的HTML
Directives 扩展的HTML属性和元素
Model 显示给用户交互的数据
Scope 储存Model的上下文(Context)供控制器、指令、表达式访问
Expressions 从Scope中访问变量和函数
Compiler 解析模板,并实例化指令和表达式
Filter 格式化表达式的值展示给用户
View 用户看到的东西(DOM)
Dat]a Bindin 在model和view之间同步数据
Controller View背后的业务逻辑
Dependency Injection] 创建并连接对象
Injector 依赖注入容器(dependency injection container)
Module 配置Injector
Service 不依赖view的可重用的业务逻辑

理解控制器

Understanding Controller

当DOM动过ng-controller指令指定一个控制器时,Angular会用指定的控制器构造函数实例化一个新控制器对象。一个新的child scope会被注入成为这个构造函数的参数——$scope。

正确地使用控制器(Controller)

Using Controllers Correctly

控制器一般不要做太多的事情,只应该包含一个view需要的业务逻辑。

保持控制器干净的一个通用的方法是把不属于这个控制器的工作封装成一个服务,然后通过依赖注入去用它。这些在Dependency Injection Services的章节讨论。

不要把控制器用来做:

  • 任何DOM操作 —— 控制器只应该包含业务逻辑。DOM操作是公认的难以测试的东西,把展示逻辑放在控制器会显著地影响业务逻辑的可测试性。Angular提供数据绑定来自动完成DOM操作。如果必须要进行你自己的一些DOM操作,就用指令(directive)把这些逻辑封装起来。
  • 格式化输入 —— 用angular form controls代替
  • 过滤输出 —— 用angular filters
  • 跨控制器共享stateless和stateful代码 —— 用angular services代替
  • 管理其他组件的生命周期

Filters

filters的API是filterProvider

本章没啥东西,不翻译了,摘选点我觉得重要的东西:

  • DOM中使用:{{ expression | filter1:arguments1:args2... | filter2 }}
  • 控制器中使用:只需要将控制器对filter的依赖写入控制器的参数,然后直接调用就行了。关键是依赖的名字:这个名字是filter的名字+"Filter"后缀,如reversefilter的名字就是reverseFilter,示例看这里
  • 自定义:angular.module(...).filter('reverse', function(){ return function(){ return result;}}),就是说,将一个返回值是过滤函数的函数传给module的filter方法的第二个参数。第一个参数是要自定的filter的名字(不含"Filter"后缀)。

Templates

Templates

在模板中能用的Angular元素和元素的属性:

  • Directive —— 作为已有DOM的属性或表现为可重用的DOM组件(译者注:一大堆拗口的废话就是说“元素属性或自定义元素”)
  • Markup —— {{}}用来输出一个表达式
  • Filter —— 格式化输出
  • Form Controls —— 用户输入验证

什么是Angular Service

What are Angular Services?

Angular Service是执行web app通用任务的函数或者对象。Angular有一系列内置的服务如:提供浏览器ajax请求的$http service。像其他Angular变量、标示符一样,内置的服务总是用$开头(如前面的$http)。你也可以定义自己的服务。

使用服务

Using Service

要使用服务的时候,需要把服务标示为依赖传给组件(controller、service、filter、directive)。Angular的依赖注入子系统会处理剩下的事情。injector子系统负责服务的实例化、解析依赖以及给组件提供依赖。

Angular的依赖注入使用“constructor” injection。它将依赖传递给组件的工厂或构造函数。由于js是一个动态类型的语言,Angular的依赖注入子系统不能用静态类型来标识服务依赖。正因如此,组件必须明确地用injection annotation来定义它的依赖。比如提供一个$inject属性:

    var MyController = function($location) { ... };
    MyController.$inject = ['$location'];
    myModule.controller('MyController', MyController);

或者提供一个"inline" injection annotion

    var myService = function($http) { ... };
    myModule.factory('myService', ['$http', myService]);

定义服务

Defining a Service

开发正可以在Angular的Module中通过注册一个名字和**服务工厂函数(service factory function)**来定义自己的服务。

服务工厂函数是为了创建一个服务的对象或函数,以便使用。这个对象或函数会被注入到指定了这个依赖的组件中。

Angular的工厂函数是懒执行的。就是说,他们只会在需要满足依赖的时候执行,并且每个服务都只会被执行一次。任何依赖服务的东西获取到服务的引用都是工厂函数生成的。

使用$location

Using $location

$location服务基于window.location来解析地址栏的URL。改变地址栏的URL会被反射到$location服务,改变$location也会反射到地址栏。

它不是为了在改变URL后整页面刷新设计的,如果要这样做,用低级的API——$window.location.href。

$location服务:

  • 暴露当前的URL,让你能:
    • watch、observe它
    • 改变它
  • 保持自身与浏览器同步,当用户:
    • 改变地址栏的URL
    • 点击浏览器的前进、后退按钮(或者历史链接)
    • 点击页面中的链接

对比一下:

window.location $location service
用途 读写浏览器的地址 一样
API 暴露原始对象并能被直接更改 暴露jquery风格的getter和setter
集成到angular的生命周期 没有 了解内部所有生命周期的阶段,并与$watch等整合
无缝集成HTML5 API 没有 是(使用fallback到老浏览器)
aware of docroot/context from which the application is loaded no - window.location.path returns "/docroot/actual/path" yes - $location.path() returns "/actual/path"

$location的Hashbang和HTML5模式

Hashbang and HTML5 Modes

$location服务可以配置两种模式来控制URL的格式:Hashbang模式(默认)和使用HTML5 History API的HTML5模式。应用在两种模式下都使用相同的API。

Hashbang模式 HTML5模式
配置 默认 {html5Mode:true}
URL格式 所有浏览器都使用hashbang URLs 在现代浏览器中使用正规的URLs,在老浏览器中使用hashbang
链接重写
需要服务器端配置

hashbang_vs_regular_url

要使用HTML5模式,必须在服务器端设置重写规则,简单来说就是你必须把所有链接指向入口文件。如index.html。

$location的HTML链接重写

HTML link rewrite

当用HTML5 history API模式的时候,你可能需要在不同的浏览器上使用不同的链接。但你真正需要做得只是指定一个标准的URL链接,比如: <a href="/some?foo=bar">link</a>

当用户点击链接的时候,在老浏览器中URL会自动变为/index.html#!/some?foo=bar

在下面这些情况中,链接不会被重写,而浏览器会进行整页的刷新

  • 链接含有target属性:<a href="/ext/link?a=b" target="_self">link</a>
  • 到其他域名的绝对链接:<a href="http://angularjs.org/">link</a>
  • 当base有定义时,通过/开头的链接指向其他base

当在根域名运行angular的时候,可能有平行的其他应用在同一目录,otherwise路由会尝试处理所有URL,包括静态文件。

要预防这个问题,你可以给应用设置base:<base href=".">然后给要被处理的URL架上.前缀。现在,不使用angular路由的链接不会有.前缀,也就不会被$routeProvider中的otherwise规则所拦截了。

$location警告

页面重载跳转

$location服务只允许改变URL,而不允许重载页面。当你需要改变URL、重载页面或者要跳转到其他页面,请用低等级的API:$window.location.href

在scope的生命周期以外使用$location

$location了解Angular scope的生命周期。当浏览器的URL改变的时候,它会更新$location并调用$apply,所有$wathers/$observers都会被通知到。在$digest期间改变$location是完全没有问题的,$location会将这个改变传递到浏览器并会通知所有的$wathers/$observers。当你要从angular外部改变$location的时候(如触发DOM事件或者测试),一定要调用$apply来传递。

$location.path() and ! or / prefixes

一个路径应该总是由/开头;如果缺失的话,$location.path()设置器会自动加入反斜线。

注意hashbang中的!前缀不是$location.path()的一部分,它实际上是hash的前缀。

未完

@ericdum ericdum closed this Dec 14, 2013

@ericdum ericdum reopened this Dec 14, 2013

@veeking

This comment has been minimized.

Show comment
Hide comment
@veeking

veeking Aug 20, 2014

我还奇怪,在设置$location.path('xx')后地址栏一直没反应,原来如此 ,哈,感谢....

veeking commented Aug 20, 2014

我还奇怪,在设置$location.path('xx')后地址栏一直没反应,原来如此 ,哈,感谢....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment