├── .gitignore ├── LANGS.md ├── LICENSE ├── README.md └── zh ├── README.md ├── SUMMARY.md ├── chapter01.md ├── chapter02.md ├── chapter03.md ├── chapter04.md ├── chapter04_1.md ├── chapter04_10.md ├── chapter04_2.md ├── chapter04_3.md ├── chapter04_4.md ├── chapter04_5.md ├── chapter04_6.md ├── chapter04_7.md ├── chapter04_8.md ├── chapter04_9.md ├── chapter04_summary.md ├── chapter05.md ├── chapter05_1.md ├── chapter05_2.md ├── chapter05_3.md ├── chapter05_4.md ├── chapter05_5.md ├── chapter05_6.md ├── chapter05_7.md ├── chapter05_summary.md ├── other ├── README.md ├── part1 │ ├── Chapter_1.md │ ├── Chapter_1_phalcon.md │ └── Part_1_Intro.md └── part2 │ └── Chapter_1.md └── pic ├── 0201_create_project.png ├── 0202_empty_project.png ├── 0203_terminal.png ├── 0204_bower.png ├── 0301_install_angular.png ├── 0302_run_index.png ├── 0303_hello_world.png ├── 0401_ng-app.png ├── 0402_ng-controller.png ├── 0403_ng-model.png ├── 0404_ng-click.png ├── 0405_ng-if_true.png ├── 0406_ng-if_false.png ├── 0407_ng-repeat.png ├── 0408_ng-repeat_html.png ├── 0409_ng-repeat_index.png ├── 0410_filter.png ├── 0411_ngclass.png ├── 0412_ngclass.png ├── 0413_ngclass.png ├── 0414_ngclass.png ├── 0415_ngclass.png ├── 0416_ngclass.png ├── 0417.png ├── 0418.png ├── 0419.png ├── 0420.png ├── 0421.png ├── 0422.png ├── 0423.png ├── 0424.png ├── 0501_first_directive.png ├── 0502.png ├── 0503.png ├── 0504.png ├── 0505.png ├── 0506.png ├── 0507.png ├── 0508.png ├── 0509.png ├── 0510.png ├── 0511.png ├── 0512.png ├── 0513.png ├── 0514.png ├── 0515.png └── 0516.png /.gitignore: -------------------------------------------------------------------------------- 1 | zh/pic/Thumbs.db 2 | -------------------------------------------------------------------------------- /LANGS.md: -------------------------------------------------------------------------------- 1 | * [中文](zh) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) 2 | Copyright (c) 2016 Harry 3 | This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/4.0/. 4 | 5 | 署名-非商业性使用 4.0 国际 6 | Copyright (c) 2016 Harry 7 | 本作品采用知识共享 署名-非商业性使用 4.0 国际 许可协议进行许可。访问 http://creativecommons.org/licenses/by-nc/4.0/ 查看该许可协议。 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Learning AngularJS 2 | ======= 3 | 4 | This is a record of my journey in learning AngularJS. The book is only written in **Chinese**. 5 | 6 | For English readers, I recommend you could go to [egghead.io](http://egghead.io) and view their videos which are very well made. 7 | -------------------------------------------------------------------------------- /zh/README.md: -------------------------------------------------------------------------------- 1 | # 学习AngularJS 1.x 2 | ## Learning AngularJS 1.x 3 | 本书是我在学习和应用AngularJS 1.x 的过程中的资料梳理。希望能对大家学习AngularJS有一定帮助。 4 | 5 | ``` 6 | 如果您在阅读过程中,有任何疑问或者发现错误,可联系: 7 | 作者: Harry 8 | 微信: hharry 9 | ``` 10 | 11 | ## 本书地址 12 | 本书使用GitBook和GitHub托管。 13 | 14 | GitBook地址:[hairui219/learning_angular](https://www.gitbook.com/book/hairui219/learning_angular/details) 15 | 16 | GitHub地址:[hairui219/learning_angular](https://github.com/hairui219/learning_angular) 17 | 18 | ## 章节目录 19 | {% include "./SUMMARY.md" %} 20 | 21 | ## 本书的读者 22 | 本书会介绍如何应用AngularJS,但是本书不会涉及到JavaScript语法以及HTML和CSS的布局模式。因此,本书对读者有一定的前置技术要求: 23 | 1. 您需要知道和理解HTML和CSS布局的方法 24 | 2. 您需要知道JavaScript的基本语法 25 | 3. (推荐)您知道一些Node.js的使用方法 26 | 4. (推荐)您知道控制台命令如何使用 27 | 28 | 如果您需要对以上某方面内容入门,我向您推荐[W3School网站](http://www.w3school.com.cn/index.html)。您可以在这个网站上快速的了解相关的知识。 29 | 30 | 另外,在JavaScript方面,如果您有一定的PHP经验,我向您推荐这本书(如果您没有PHP经验,这本书也可以阅读): 31 | - JavaScript for PHP Developers (中文版) - Stoyan Stefanov 著 - 李强 译 32 | 33 | 这本书只有141页(定价28元,网站还有折扣),阅读起来非常轻松,如果您有编程经验,一个下午就可掌握JavaScript的基本语法和用法(同时也可能学会PHP的语法)。 34 | 35 | > 京东特价优惠时我购买了几十本与JavaScript相关的书籍,这本是我认为最靠谱的入门书。 36 | 37 | ## 我应用AngularJS的方法 38 | 在进行前端开发的工作之前,我担任过几年的移动互联网产品经理,设计了几款应用(参与了一小部分的开发工作)。之后我改做应用和手机游戏的后端开发(主要使用PHP)。 39 | 40 | 在这几年的工作经验中,我形成了一套app的构建思路。因此,在制作网站前端时,我也希望采用类似的方法(我不喜欢直接在php代码中直接嵌入html模板的方案,那样做感觉上比较混乱,难以管理。 41 | 42 | 因此,我将AngularJS作为一个类似于app的载体,当网站代码在客户端载入完成后,再通过api请求获取数据。 43 | 44 | ### 这样做的好处 45 | 这样实现后,我认为主要有以下几个方面的好处: 46 | 1. 数据通过API(https)获取,过程并不向用户开放,起到了隐蔽后端服务器的效果 47 | 2. 可以对API的访问限制和安全性进行更完善的设计实现 48 | 3. 前端网站托管在阿里云的OSS上(以静态网站的方式部署),这样页面部分不再占用服务器的流量和空间 49 | 4. 便于之后的扩展,前端网站可以使用阿里云的CDN直接进行访问加速;后端在使用API模式通讯的情况下,本来就可以极大的提高负载能力(网络带宽优化),如果需要扩展,可以提高机器配置或者增加机器数量。 50 | 51 | 幸运的是,**AngularJS推荐这么做**。 52 | 53 | ## 为什么选择AngularJS 1.x 54 | 对于选择AngularJS,业(zhi)界(hu)其实有一个调侃的说法: 55 | 56 | > 写Java的写不来JavaScript的用AngularJS 57 | 58 | 虽然这个说法比较武断,但是其中也体现出来一个明显的信息,**如果你之前有Java或其他后端语言的编程经验,AngularJS是让你快速上手Web前端开发的很好的选择**。至少对我而言是如此。 59 | 60 | ## 我选择AngularJS的历程 61 | > 以下内容部分读者可能会感到有些偏激,但是这是对我(一个拥有一些其他编程经验的前端入门者)的心路记录。 62 | 63 | 2015年初,在准备通过完全的Web方式实现一个B/S模式的企业服务网站之后,我开始进行技术方面的准备。在此之前,我只有Android客户端和PHP服务端的工作经验。另外,我对web的基本开发技能使用过一些,掌握了HTML+CSS的一些应用技巧。JavaScript的语法和基本特性方面也通过Node.js在工作中的应用熟悉了。 64 | 65 | 但是,在网站前端技术准备过程中,我发现我对DOM的操作一窍不通。即使是购买了若干本入门的书籍,通过阅读书籍,我知道了如何通过document.getElementById('xxx')或者jQuery的$('xxx')来获取元素和填入代码之类的工作。但学会基本的语法之后,我仍然是对于具体如何操作DOM来实现具体的功能完全没有头绪。这是一种什么感觉呢?就像是在读大学时学习C/C++/Java语言,我们可以手工的去实现一些基本的算法或数据结构。但是学完了之后,我们可以直接使用C/C++或Java制作基于Windows的客户端程序了吗?一点也不。学习DOM入门给我的感觉与之一模一样。 66 | 67 | 因为当时并不知道还有JavaScript框架这种东西存在,我去网上搜索教程时也是一头雾水。因此,我想了一个笨办法,直接在一个国外的网站上购买了一套后台管理系统界面的模板。浏览了下源代码之后,我发现源码提供了两套版本,一套完全基于jQuery+BootStrap的版本,和一套基于AngularJS的版本。两个版本的界面布局一模一样,但是基于AngularJS的版本提供了一些如单页应用(在同一个界面直接刷新部分界面而不是整页刷新)的特性。 68 | 69 | 然后便是一系列的在网上搜索了解AngularJS的过程,看完它基本的Tutorial(PhoneCat)之后,我马上被它的特性震惊了。因为, 70 | 1. AngularJS的整个结构体系非常符合我的思路 71 | 2. 双向绑定的特性实在是太和我胃口了,这让我完全不用再操心DOM 72 | 73 | 因为这两点特性,我义无反顾的加入了使用AngularJS的大军。 74 | 75 | > 题外话: 76 | 77 | > 国外网站购买的这种模板,都是由专业的前端人员开发,提供的功能都非常丰富完整。另外,他们对管理工具的使用也很正规(使用bower或其他工具来管理第三方库等),代码结构和注释也非常完善。 78 | 79 | > 对我而言,这笔投资绝对物有所值(当时花费了我19美金)。 80 | 81 | 接下来我所做的事情,就是拿着这个模板的代码,修改html和增加controller/service,调整ui-router的配置,最终完成了网站的第一个版本。花的时间大约是2个月出头(前端+后端+部署调试,开发工作全部由我一人完成)。 82 | 83 | 从今天来看,我的做法完全不符合AngularJS的最佳实践。虽然我未在网站中使用jQuery等类库,但是我也同样没有使用AngularJS推荐使用的directive方式(完全没有使用,这也是我准备在更深入的学习AngularJS和重新构建网站的第二版的主要原因)。 84 | 85 | 但是,不管怎么说,我把东西做出来了,而且整个网站是可用的,从程序结构上也是可维护和修改的。 86 | 87 | ## 为什么写这本书 88 | 由于业务需要,我准备重新制作网站的v2版本。在这个版本中,会有很多新的功能需求(功能扩大非常多)。因此,完全重构整个网站是可以接受的。另外,我之前只是误打误撞的制作出来一个"可用"的网站,为了使用更地道的方式制作这个新版网站,我现在正在重新学习AngularJS。 89 | 90 | 写这本书,一方面是为了记录学到的AngularJS的技术,便于我日后查询;另一方面也是为了给自己一点压力,让自己沉下心来掌握这门技术。 91 | 92 | 我在AngularJS方面也是一名菜鸟,虽然我会尽力保证信息的正确性,但也还请您在阅读的过程中批判的接收信息。如果有何问题,请通过邮件或微信联系我(联系地址在此页面上方)。 93 | 94 | ## 另:为什么没有选择Angular 2 95 | 其实在重构时,我优先的选择是Angular 2 & TypeScript。因为它引入了很多新的特性,比如应用了最新的ES标准,大量优化了Angular工作的效率等等。 96 | 97 | 但是,下面3个原因导致了我放弃了Angular 2作为新版本网站的技术选择。 98 | 1. 我自认为是一个比较追求新技术的人,但是当我测试Angular 2时,发现我电脑上安装的Chrome v44版本无法运行,当我下载更新到v47后才能正常运行(官网介绍v46以上才支持es6)。 99 | 2. 新版本Angular 2抛弃了controller/service,完全用directive,这点与我的技术构想不符。 100 | 3. 即使在我评估Angular 2时已经是beta版本,但是官网仍然推荐不要将其用于生产环境。 101 | 102 | 我的网站运行的是对公业务,且对合作方使用的浏览器有一定的影响能力,但是我没有信心让所有客户都安装上Chrome的最新版本。 103 | 104 | 与我技术构想不符则是对我本人来说更重要的一个原因,因为我无法认同Angular 2的优化方向。同时,根据我的工作经验来看,这样革命性的优化通常是内部一群理念不合的人另起炉灶,结果可能喜忧参半,不一定会最终成功。 105 | 106 | TypeScript的引入我不好评价,但是强类型定义和模型化并不太符合我的业务模式(api一次性获取界面需要的所有数据,这些数据已经在服务端进行好了类型定义和完整性处理,本地主要是实现对CRUD的调用)。 107 | 108 | 综上,我放弃了在新版本的网站中应用Angular 2技术,而选择继续使用AngularJS 1.x。 109 | 110 | # 版权声明 LICENSE 111 | 112 | ``` 113 | 署名-非商业性使用 4.0 国际 114 | 版权所有 (c) 2016 Harry 115 | 本作品采用知识共享 署名-非商业性使用 4.0 国际 许可协议进行许可。访问 116 | http://creativecommons.org/licenses/by-nc/4.0/ 查看该许可协议。 117 | 118 | Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) 119 | Copyright (c) 2016 Harry 120 | This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 121 | International License. To view a copy of this license, visit 122 | http://creativecommons.org/licenses/by-nc/4.0/. 123 | ``` 124 | -------------------------------------------------------------------------------- /zh/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | - [简介](README.md) 3 | - [环境的准备](chapter01.md) 4 | - [项目的创建和配置](chapter02.md) 5 | - [AngularJS的第一步](chapter03.md) 6 | - [学习和使用AngularJS](chapter04.md) 7 | - [基本表达式](chapter04_1.md) 8 | - [AngularJS初始化 ng-app](chapter04_2.md) 9 | - [控制器 ng-controller](chapter04_3.md) 10 | - [数据绑定 data-binding](chapter04_4.md) 11 | - [条件判断 ng-if / ng-show / ng-hide](chapter04_5.md) 12 | - [重复语句 ng-repeat](chapter04_6.md) 13 | - [过滤器 filter](chapter04_7.md) 14 | - [样式选择器 ng-class/ng-style](chapter04_8.md) 15 | - [下拉列表选项 ng-options](chapter04_9.md) 16 | - [引入ng-include和模板ng-template](chapter04_10.md) 17 | - [本章总结](chapter04_summary.md) 18 | 19 | - [深入学习AngularJS - Directive](chapter05.md) 20 | - [制作一个自定义的Directive](chapter05_1.md) 21 | - [Directive的命名和使用规则](chapter05_2.md) 22 | - [让Directive支持传入数据](chapter05_3.md) 23 | - [使用templateUrl获取模板](chapter05_4.md) 24 | - [让Directive动起来`link()`](chapter05_5.md) 25 | - [把Directive变为一个容器`transclude`](chapter05_6.md) 26 | - [Directive之间互相通讯](chapter05_7.md) 27 | - [本章总结](chapter05_summary.md) 28 | -------------------------------------------------------------------------------- /zh/chapter01.md: -------------------------------------------------------------------------------- 1 | 环境的准备 2 | ====== 3 | 4 | 开发Web网站,使用合适的工具和环境会极大的提升开发的效率。本章将讲述如何准备用于AngularJS项目开发的环境。 5 | 6 | 本书将会使用如下工具和库: 7 | * [WebStorm](https://www.jetbrains.com/webstorm/) - 前端开发 8 | * [Chrome](https://www.google.com/chrome/browser/desktop/index.html?standalone=1) - Google Chrome浏览器 9 | * [AngularJS](https://angularjs.org/) - 前端JS框架 10 | * [Angular Material](https://material.angularjs.org/latest/) - 前端界面框架 11 | * [bower](http://bower.io/) - 获取包括AngularJS在内的各种开发库 12 | 13 | 为了使用bower,您可能还需要安装如下工具: 14 | * [cnpm](http://npm.taobao.org/) - 国内用户推荐,淘宝的npm加速服务 15 | * [npm](https://www.npmjs.com/) - Node.js的包管理软件 16 | * [Node.js](https://nodejs.org/en/) - 基于Chrome V8引擎的本地/服务端JS运行环境 17 | 18 | ``` 19 | 以上内容除去WebStorm外,都可以免费获得。WebStorm可以获取免费试用30天的版本。 20 | 因此,您在学习本书的过程中,并不需要花费购买任何软件。 21 | ``` 22 | 23 | ## WebStorm 24 | 在过去的开发中,WebStorm一直是我对编辑器的首选。WebStorm是商业化的产品,如果长期使用,需要花钱购买(目前已经支持支付宝购买)。价格的话,如果你是一名专职的前端工作人员,可以自行购买或者要求公司购买,个人购买的费用是第一年$59美金,我个人认为还是非常超值的(对比工作效率的提升而言)。另外,出于个人习惯,我使用的是英文版的WebStorm,目前网络上也存在有汉化包,如果希望使用汉化界面的朋友可以自行搜索尝试。 25 | 26 | 在学习本书的过程中,您可以使用WebStorm的30天尝试版本(直接下载安装即可)。30天的时间对于学习AngularJS和进行一些初级的开发尝试完全足够了。 27 | 28 | 本书写作时使用的WebStorm版本是11.0.3。 29 | 30 | 31 | >WebStorm自8.x版本起就可以正确的开发AngularJS网站(再往前的版本没有评估)。 32 | >使用最新的11.0.3版本是在准备本书内容过程中,评估了Angular 2。 33 | >而WebStorm是从11版本才开始部分支持Angular 2的TypeScript开发。 34 | 35 | ``` 36 | 另:使用哪种编辑器更多的是个人的偏好。如果您有其他喜欢的编辑器,可以自行选择。 37 | ``` 38 | 39 | ## Chrome 40 | Chrome浏览器的开发者工具可以极大的方便开发时的调试工作,目前国内大量浏览器也是基于Chrome的开源内核开发,在通用性上也有保证。另外,Chrome上有支持WebStorm的插件“JetBrains IDE Support”。 41 | 42 | 由于国内网络原因,Chrome浏览器必须要连接至国外路由才能下载。另外推荐您点击以下链接进行下载,这样可以直接下载完整的安装包(直接在Google搜索Chrome的官网页面下载的是一个小型下载器,在国内无法正确安装)。 43 | 44 | [Chrome完整版本下载链接](https://www.google.com/chrome/browser/desktop/index.html?standalone=1) 45 | 46 | ``` 47 | https://www.google.com/chrome/browser/desktop/index.html?standalone=1 48 | ``` 49 | 本书写作时使用的Chrome版本是47.0.2526.106 m。 50 | 51 | 52 | >Chrome的版本对于应用AngularJS并不关键,本书特意安装目前的最新版本,是因为要同时评估Angular 2, 53 | >而Angular 2必须要在非常新的浏览器上才能正确运行(v 46+)。 54 | 55 | 56 | ## Node.js 57 | Node.js在本书中主要的使用用途是运行bower工具,用以安装AngularJS极其相关的库文件。通过官网可以直接下载Node.js的安装包(Windows/OS X都有对应的安装包)。 58 | 59 | 本书使用的Node.js版本是5.4.1(目前最新的Stable稳定版本)。推荐安装较新的稳定版本。 60 | 61 | ## 其他工具 62 | 在安装好Node.js后,可以通过Node.js的npm命令安装最新版本的npm/cnpm/bower(如果已经存在,自动安装最新版本)。 63 | 64 | 使用命令如下: 65 | 66 | Windows上打开cmd,OS X上打开Terminal。 67 | 68 | ```bash 69 | //Windows 70 | > npm install -g npm --registry=https://registry.npm.taobao.org 71 | > npm install -g cnpm --registry=https://registry.npm.taobao.org 72 | > npm install -g bower --registry=https://registry.npm.taobao.org 73 | 74 | //可选,将npm默认设置从淘宝服务器上获取数据 75 | > npm config set registry "https://registry.npm.taobao.org" 76 | 77 | 78 | 79 | //OS X (会需要您输入本机的密码) 80 | $ sudo npm install -g npm --registry=https://registry.npm.taobao.org 81 | $ sudo npm install -g cnpm --registry=https://registry.npm.taobao.org 82 | $ sudo npm install -g bower --registry=https://registry.npm.taobao.org 83 | 84 | //可选,将npm默认设置从淘宝服务器上获取数据 85 | $ npm config set registry "https://registry.npm.taobao.org" 86 | ``` 87 | 88 | 所有命令后面都跟上了一个*--registry=https://registry.npm.taobao.org*标志,这是使用了淘宝提供的npm镜像服务来安装所需的软件,这样访问的速度会加快非常多。如果您优先运行了后面的可选的命令,那么之前三个命令的此标志项都可以去除。 89 | 90 | OS X的命令和Windows类似,但是前面都加了一个sudo,用于提权后把这些工具安装到Node.js的公共库中。 91 | 92 | 安装完成后,请手动命令确认这几个工具的版本。(如果您安装时不成功,请先确认Node.js工具的版本是否是最新的) 93 | 94 | 安装好后,您的几个工具的版本应该如下(或者更高): 95 | ```bash 96 | $ npm -v 97 | 3.5.3 98 | 99 | $ cnpm -v 100 | 3.4.0 101 | 102 | $ bower -v 103 | 1.7.2 104 | ``` 105 | 106 | ## 其他工具 107 | 其他的工具和库,我们将不再需要从网站上下载安装,直接通过bower在项目内进行下载使用。 108 | -------------------------------------------------------------------------------- /zh/chapter02.md: -------------------------------------------------------------------------------- 1 | # 项目的创建和配置 2 | 使用WebStorm可以直接创建AngularJS项目,且会自动帮助你配置好项目并自动下载AngularJS等库。但是我们这里将创建一个新的空项目(Empty Project),然后一步一步的将各个需要的内容填充进来,这样我们会对使用AngularJS开发有一个更好的了解。 3 | 4 | 在WebStorm中,选择`File > New Project`,然后选择Empty Project,在右边的Location设置好项目的位置,然后点击界面右下角的Create即可。 5 | 6 | ![图2-1 创建项目](./pic/0201_create_project.png) 7 | 8 | 下面我们将一步一步的完善整个项目的结构。 9 | 10 | ## 创建基本的文件结构 11 | 首先建立一个`public`目录,并在`public`目录中建立`js`、`css`、`img`三个目录。如下图所示: 12 | 13 | ![图2-2 创建目录](./pic/0202_empty_project.png) 14 | 15 | 大家对于`js/css/img`三个目录的设置应该比较熟悉,他们分别用于存放对应的文件,`img`用于存放图片文件。 16 | 17 | 但是,为什么要把他们放置到`public`目录中呢? 18 | 19 | ### `public`目录设置的意义 20 | 从字面意思即可理解,`public`目录是用来存放供外部用户访问的内容的根目录。非`public`目录下的内容,既是我们不期望用户通过网络链接直接可以访问到的内容。会有哪些内容呢? 21 | - 产品的文档 22 | - 一些项目配置文件(如`bower`的配置文件) 23 | - 测试文档 24 | 25 | 这些文件我们是绝对不希望用户可以直接访问到的,通过设置一个public目录,并在部署时将网站的根目录直接指向到`public`目录,即可保证目录外的内容不被暴露到网络当中。 26 | 27 | 另外,这样设置的主要原因是为了使用git将整个项目都管理起来。通过git版本控制的方式来保证项目代码的完整性和安全性。具体的git的操作方法就不在本文中叙述了。 28 | 29 | ## 配置并初始化bower 30 | bower的配置可以通过手动创建文件或者命令行的方法来进行。我推荐使用命令行的方式来进行创建,这样可以更好的理解配置生成的文件的内容。如果不想通过命令行创建,也可以跳过下面命令行创建的部分,直接在下方生成的文件解析的部分,将文档内容拷贝过去。 31 | 32 | ### 打开命令行工具 33 | WebStorm内置了命令行工具(调用系统的命令行功能),在左下角点击`Terminal`即可启用。 34 | 35 | ![图2-3 命令行工具](./pic/0203_terminal.png) 36 | 37 | ### 初始化bower 38 | 在命令行下运行`bower init`,你将会看到如下的若干选项,并会自动的在项目的根目录生成一个`bower.json`。 39 | 40 | **注:以下的汉字部分都是额外加入的注释。** 41 | 42 | ```bash 43 | //运行命令 44 | >bower init 45 | 46 | //第一次运行的时候会弹出,是否愿意提交匿名的统计信息。随意选择 47 | ? May bower anonymously report usage statistics to improve the tool over time? Yes 48 | //项目名称 49 | ? name learning_angularjs 50 | //项目说明 51 | ? description 52 | //主文件 53 | ? main file 54 | //项目的类型 55 | ? what types of modules does this package expose? 56 | //项目的关键字 57 | ? keywords 58 | //作者和联系方式 59 | ? authors Harry 60 | //授权方式,如果您期望这是一个私人项目,可以输入No License 61 | ? license MIT 62 | //项目主页 63 | ? homepage 64 | //是否要把当前已经安装的模块设置为项目的依赖项? 65 | ? set currently installed components as dependencies? Yes 66 | //将常用的忽略文件项添加到列表? 67 | ? add commonly ignored files to ignore list? Yes 68 | //将项目设置为私有,防止其被误发布到网络上? 69 | ? would you like to mark this package as private which prevents it from being accidentally published to the registry? Yes 70 | 71 | //以下是生成的配置文件的预览 72 | { 73 | name: 'learning_angularjs', 74 | authors: [ 75 | 'Harry ' 76 | ], 77 | description: '', 78 | main: '', 79 | moduleType: [ 80 | ], 81 | license: 'MIT', 82 | homepage: '', 83 | private: true, 84 | ignore: [ 85 | '**/.*', 86 | 'node_modules', 87 | 'bower_components', 88 | 'test', 89 | 'tests' 90 | ] 91 | } 92 | 93 | ? Looks good? Yes 94 | ``` 95 | 96 | 命令运行完毕后,会在项目的根目录生成一个`bower.json`文件,里面的内容如下: 97 | 98 | ```json 99 | //bower.json 100 | { 101 | "name": "learning_angularjs", 102 | "authors": [ 103 | "Harry " 104 | ], 105 | "description": "", 106 | "main": "", 107 | "moduleType": [ 108 | ], 109 | "license": "MIT", 110 | "homepage": "", 111 | "private": true, 112 | "ignore": [ 113 | "**/.*", 114 | "node_modules", 115 | "bower_components", 116 | "test", 117 | "tests" 118 | ] 119 | } 120 | ``` 121 | 122 | 如果您不希望bower配置文件这么复杂,那么可以手工最简化的创建`bower.json`。 123 | 124 | ```json 125 | //最简化bower.json 126 | { 127 | "name": "learning_angularjs" 128 | } 129 | ``` 130 | 131 | 只需要一个`name`字段即可让bower好好工作了。 132 | 133 | ## `.bowerrc`配置文件 134 | 由于我们建立了`public`目录,并且项目的根目录与网站根目录不同,因此,我们需要新建一个额外的`.bowerrc`文件,告诉`bower`将组件库下载到特定的目录。 135 | 136 | 在项目根目录创建`.bowerrc`文件,并在其中加入如下内容: 137 | 138 | ```json 139 | //.bowerrc 140 | { 141 | "directory": "public/components" 142 | } 143 | ``` 144 | 145 | 以上配置文件会告诉`bower`将文档下载到`./public/components`目录中。 146 | 147 | ### 配置完成 148 | 至此,我们对`bower`的配置已经全部结束!现在项目看起来应该长这个样子: 149 | 150 | ![图2-4 Bower配置完成后](./pic/0204_bower.png) 151 | -------------------------------------------------------------------------------- /zh/chapter03.md: -------------------------------------------------------------------------------- 1 | # AngularJS的第一步 2 | 在前面的章节,我们已经创建好了项目,并配置好了bower工具。本章开始,我们将进入正式的学习使用AngularJS的过程。首先,我们将从安装AngularJS开始。 3 | 4 | ## 在项目中安装AngularJS的基本库 5 | [AngularJS官网](https://angularjs.org/)提供了通过Bower安装的命令行,我们需要做的,就是在WebStorm的命令行工具中,运行如下命令: 6 | 7 | ```bash 8 | $ bower install angular#1.5.0-rc.0 --save 9 | ``` 10 | 11 | 结果如下所示: 12 | 13 | ```bash 14 | >bower install angular#1.5.0-rc.0 --save 15 | 16 | bower angular#1.5.0-rc.0 cached git://github.com/angular/bower-angular.git#1.5.0-rc.0 17 | bower angular#1.5.0-rc.0 validate 1.5.0-rc.0 against git://github.com/angular/bower-angular.git#1.5.0-rc.0 18 | bower angular#1.5.0-rc.0 cached git://github.com/angular/bower-angular.git#1.5.0-rc.0 19 | bower angular#1.5.0-rc.0 validate 1.5.0-rc.0 against git://github.com/angular/bower-angular.git#1.5.0-rc.0 20 | bower angular#1.5.0-rc.0 install angular#1.5.0-rc.0 21 | 22 | angular#1.5.0-rc.0 public\components\angular 23 | ``` 24 | 25 | **命令解释** 26 | 27 | 这行命令告诉`bower`在这个项目中安装`angular#1.5.0-rc.0`,也即是AngularJS的1.5.0-rc.0版本(当前的最新版本)。 28 | 29 | **`--save`标志** 这个额外的标志,是告诉`bower`把我们的安装记录放置入`bower.json`文件。这样,我们以后可以直接通过`bower`对此项目使用的AngularJS或其他库进行更新。 30 | 31 | 此时,当我们打开`bower.json`,我们会发现文档中的内容变多了,如下所示: 32 | 33 | ```json 34 | //bower.json 35 | { 36 | "name": "learning_angularjs", 37 | "dependencies": { 38 | "angular": "1.5.0-rc.0" 39 | } 40 | } 41 | ``` 42 | 43 | 同时,项目中会多出`./public/components/angular`目录,所有的AngularJS的文件都在这个目录中存放。 44 | 45 | ![图3-1 安装好AngularJS后的目录结构](./pic/0301_install_angular.png) 46 | 47 | ## 建立`index.html`文件 48 | 在`./public`目录下建立`index.html`文件(右键public目录,`New > HTML File`,然后输入`index`,点击`OK`)。WebStorm会自动帮助我们加入基本的HTML内容。 49 | 50 | ```html 51 | 52 | 53 | 54 | 55 | 学习AngularJS 1.x 56 | 57 | 58 | 59 | 60 | 61 | ``` 62 | 63 | 我将`lang`从`en`改为了`zh`,标明此网站是简体中文的。同时调整了`title`。HTML的基础并不属于本书的范围,因此不在此细述。 64 | 65 | ## 引入AngularJS的库文件 66 | 引入AngularJS库文件很简单,一行HTML语言加入HTML的head部分即可: 67 | 68 | ```html 69 | 70 | ``` 71 | 72 | 注:这里引入的angular.js是完整的版本(1M大小),如果在运行环境中,您应该将angular.js替换为angular.min.js(148KB)。 73 | 74 | > 小贴士: 将js文件放在head部分和body部分有何区别? >放在head部分的JavaScript文件,会在body渲染完毕后才开始执行。从AngularJS工作的特性来看,推荐所有的JavaScript文件都放在body部分引入。 75 | 76 | ## 第一个程序Hello World 77 | 是时候来测试下我们是否成功的引入了AngularJS了。我们在元素中加入一个ng-app="",然后加入一行代码`{{"Hello World!"}}`。如下所示: 78 | 79 | ```html 80 | 81 | 82 | 83 | 84 | 学习AngularJS 1.x 85 | 86 | 87 |

{{"Hello World!"}}

88 | 89 | 90 | 91 | ``` 92 | 93 | ## 运行Hello World 94 | 右键选择`index.html`,然后选择 `run "index.html"`,然后你就可以在新打开的浏览器中看到运行的效果。 95 | 96 | ![图3-2 运行index.html](./pic/0302_run_index.png) 97 | 98 | > 如果浏览器没有自动打开? 99 | 100 | > 我在Windows电脑上遇到了相同的问题,请将WebStorm使用管理员权限打开。 101 | 102 | 运行效果如下图所示: 103 | 104 | ![图3-3 Hello World](./pic/0303_hello_world.png) 105 | 106 | 看不到`{{`和`}}`,就说明AngularJS已经成功运行起来了! 107 | 108 | 如果AngularJS没有成功运行,那么您看到的应该是如下内容: 109 | 110 | ``` 111 | {{"Hello World!"}} 112 | ``` 113 | 114 | 如果出现以上结果,请您按书的前面内容仔细检查您的代码。 115 | 116 | Hello World到此结束,下面我们将进入AngularJS的世界,学习它,理解它,使用它! 117 | -------------------------------------------------------------------------------- /zh/chapter04.md: -------------------------------------------------------------------------------- 1 | # 学习AngularJS的规划 2 | 我们已经完成了基本的准备工作,从本章开始,我们将专注于学习和应用AngularJS。 3 | 4 | 作为一个功能完整的框架,AngularJS提供了一套开发理念和方法,我们只需要掌握这套理念和方法即可明确如何实现我们需要的功能。 5 | 6 | 根据我个人的认知,我设计了如下的学习路线图: 7 | 8 | 第四章 基本语法 9 | 1. 基本表达式 10 | 2. AngularJS初始化 `ng-app` 11 | 3. 控制器 `ng-controller` 12 | 4. 数据绑定 data-binding 13 | 5. 条件判断语句`ng-if` / `ng-show` / `ng-hide` 14 | 6. 重复语句 `ng-repeat` 15 | 7. 过滤器 `filter` 16 | 8. 样式选择器 `ng-class`/`ng-style` 17 | 9. 下拉列表选项 `ng-options` 18 | 10. 引入`ng-include`和模板`ng-template` 19 | 20 | 深入学习 21 | 1. `Directive` 22 | 2. 数据获取$http 23 | 3. 如何使用第三方的AngularJS扩充库 24 | 4. ui-route 25 | 5. 页面模板获取和植入 26 | 6. 全局事件监听 27 | 7. 如何调试AngularJS代码 28 | 8. 如何使用自动化测试工具 29 | 30 | 表单、数据验证 31 | 32 | 界面库的引入 33 | 1. Angular-Material 34 | 35 | 案例实践 36 | 1. 登陆、注册 37 | 2. 权限控制 38 | 3. ... 39 | -------------------------------------------------------------------------------- /zh/chapter04_1.md: -------------------------------------------------------------------------------- 1 | # 基本表达式 2 | 在第三章的结尾,我们制作了一个基本的Hello World应用。在其中,我们使用了如下的语法: 3 | 4 | ```javascript 5 |

{{"Hello World!"}}

6 | 7 | //上方的“{{”和“}}”既是AngularJS的基本表达式 8 | 9 | //如果AngularJS被成功的引入,那么最终的页面将不会显示双括号,而是直接显示Hello World. 10 | ``` 11 | 12 | 我们可以尝试下将表达式中的内容替换为如下内容,并观察运行的结果: 13 | 14 | ```javascript 15 | {{ 1+1 }} //网页会显示2 16 | 17 | {{ 'a' + 'bc' }} //网页会显示abc 18 | ``` 19 | 20 | 从上我们可以看出,双括号`{{`和`}}`内的内容,其实是一个JavaScript表达式,并将表达式进行计算的结果显示在此处。这也是AngularJS最吸引人的特性,因为它还支持将JavaScript中的数据显示在此处(我们将在后面的内容中介绍如何操作)。 21 | 22 | 并且,如果此处输出的是JavaScript中的变量,此处的显示会**自动**的随JavaScript变量的变化而变化。 23 | -------------------------------------------------------------------------------- /zh/chapter04_10.md: -------------------------------------------------------------------------------- 1 | # 引入`ng-include`和模板`ng-template` 2 | 引入`ng-include`和模板`ng-template`是定义和使用HTML代码碎片的功能。用于将HTML切碎分别存储,并根据需求再去获取对应的代码块,达到加速访问和代码复用的效果。 3 | 4 | 下面,我们将分别介绍`ng-include`和`ng-template`。 5 | 6 | ## 引入`ng-include` 7 | 当HTML代码过于复杂,或者期望建立单页应用(Single-page Application - SPA)时,需要将部分HTML打包成独立的文件。这时候,我们在引入这个独立HTML文件时,可以使用`ng-include`功能。 8 | 9 | 使用方法如下: 10 | 11 | ```html 12 | 13 | 14 |
15 | 16 | 17 |
18 | 19 |
20 | ``` 21 | 22 | 从上面的例子可以看出,`ng-include`支持直接传入静态文本、传入变量、传入函数(返回网页地址)的方式来进行调用。 23 | 24 | 另外,`ng-include`的用法也可以直接作为标签名使用,如: 25 | 26 | ```html 27 |
28 | 29 | 30 | ``` 31 | 32 | 这些用法的效果都是一样的。 33 | 34 | ### 其他属性 35 | `ng-include`还有`onload`和`autoscroll`的属性。 36 | 37 | 但是我目前不清楚具体的使用方法和效果,如果有读者清楚,可与我联系以便更新上此段内容。 38 | 39 | ## 模板`ng-template` 40 | `ng-template`用于将多个HTML片段存放于一个HTML文件中。并且可以根据需求分别调用其中的某一个片段。 41 | 42 | `ng-template`的用法如下: 43 | 44 | ```html 45 | 48 | ``` 49 | 50 | `ng-template`需要将` 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 | 以上代码有两个问题需要注意: 34 | 35 | ### AngularJS的作用域 36 | `ng-app`标签可以放置在``标签或者``标签上,也可以放置在HTML页面的任何一个标签上。 37 | 38 | 这里,我们就需要注意AngularJS对于**作用域**的定义。我们先通过如下的例子来看看作用域的具体表现: 39 | 40 | ```html 41 | 42 | 43 | 44 | 45 | 46 | {{"学习AngularJS 1.x"}} 47 | 48 | 49 |

{{"Hello World!"}}

50 | 51 | 52 | 53 | 54 | ``` 55 | 56 | 以上代码的运行结果如下: 57 | 58 | ![图4-1 ng-app在body时的运行结果](./pic/0401_ng-app.png) 59 | 60 | 我们可以看到,网页标题中的AngularJS表达式并没有执行,这是因为网页的``标签中的内容,并不在AngularJS的管理之下。 61 | 62 | 如果我们将`ng-app`声明放置在``元素中,那么AngularJS**只会**针对``元素中的内容进行处理。**这也是AngularJS的核心特性之一**,它让我们的JavaScript代码有了作用域的概念,降低了代码之间不期望的一些互相影响。 63 | 64 | 这个特性我们在后面会大量的使用,将网页分为多个部分,并分别交于不同的JavaScript代码进行管理,各个部分之间互相独立,这样即可在网页中实现逻辑复杂的功能。 65 | 66 | ## 引入文件的顺序 67 | 引入JavaScript文件的顺序是有差异的,如果我们将上面代码的`angular.js`和`app.js`文件呼唤,那么网页将不能正常的展示。并且我们可在Chrome的"开发者工具"中看到报错信息。 68 | -------------------------------------------------------------------------------- /zh/chapter04_3.md: -------------------------------------------------------------------------------- 1 | # 控制器`ng-controller` 2 | 控制器`ng-controller`是使用AngularJS的核心功能之一。在前一节我们已经了解了作用域的概念,`ng-controller`则是真正应用作用域来制作功能的核心部分。 3 | 4 | 应用`ng-controller`和应用`ng-app`类似,下面我们来尝试创建一个控制器吧! 5 | 6 | 还是在app.js中,我们创建一个控制器,代码如下: 7 | 8 | ```javascript 9 | //app.js 10 | var App = angular.module("App", []); 11 | 12 | App.controller("FirstCtrl", function($scope){ 13 | $scope.data = { 14 | message : "Hello" 15 | }; 16 | }); 17 | ``` 18 | 19 | 同时,我们在`index.html`中进行一些代码修改,最终代码如下: 20 | 21 | ```html 22 | 23 | 24 | 25 | 26 | 27 | {{"学习AngularJS 1.x"}} 28 | 29 | 30 | 31 |
32 |

{{data.message + " World!"}}

33 |
34 | 35 | 36 |

下面的内容不会显示

37 |

{{data.message}}

38 | 39 | 40 | 41 | 42 | 43 | ``` 44 | 45 | 刷新页面,我们可以看到运行的效果: 46 | 47 | ![图4-2 ng-controller运行结果](./pic/0402_ng-controller.png) 48 | 49 | 下面,我们再来分析下`ng-controller`的具体形式: 50 | 51 | ## `ng-controller`详解 52 | ### JavaScript部分 53 | 我们先分析`ng-controller`的JavaScript编码部分 54 | 55 | ```javascript 56 | //原有的ng-app声明部分 57 | var App = angular.module("App", []); 58 | 59 | /** 60 | * App.controller 声明ng-controller的方法 61 | * “FirstCtrl” 这个ng-controller的名称 62 | * function($scope){} 这个ng-controller的实体,并注入$scope(下文详解) 63 | */ 64 | App.controller("FirstCtrl", function($scope){ 65 | $scope.data = { 66 | message : "Hello" 67 | }; 68 | }); 69 | ``` 70 | 71 | #### `function($scope){}`详解 72 | `funtion(){}`封装的函数,会被绑定到`FirstCtrl`上。这个概念相对容易理解,我们需要注意的,是我们在`function`中传入的**参数**`$scope`。 73 | 74 | 与一般的函数声明时的参数不同,此处的参数是**不可随意命名**的,AngularJS会解析参数的名称,并转化为对应的对象传入。 75 | 76 | 这里使用的`$scope`,用于将`ng-controller`中的数据和HTML代码绑定起来,传入`$scope`的数据,可以直接在HTML代码中调用。在上面的例子中,我们对`$scope`传入了`{data:{message:"Hello"}}`对象,并在HTML代码中直接使用了`data.message`来调用。 77 | 78 | `data`命名并不是固定用法,我们也可以使用`$scope.shuju = {m:"hello"}`。(这里只是为了表明变量命名的约束,如果可能,请不要使用拼音命名的变量)。 79 | 80 | 值得注意的是,`$scope`之下除了可以传入数据外,还可以传入其他函数,比如我们声明一个`onClick`函数传入`$scope`之后,可在HTML页面中调用这个功能,实现比如按钮点击触发功能的效果。 81 | 82 | ### HTML中调用`ng-controller`中的数据 83 | 84 | ```javascript 85 |

{{data.message + " World!"}}

86 | ``` 87 | 88 | 在`$scope`中传入数据后,通过表达式可以直接调用。 89 | 90 | ### 为什么要额外封装一层 91 | 在AngularJS中,最简单传入数据的方法其实可以更简单,但是**不推荐这样做**。 92 | 93 | 最简单的做法 94 | 95 | ```javascript 96 | //JavaScript 97 | $scope.message = "Hello"; 98 | ``` 99 | 100 | ```html 101 | //HTML 102 |
103 | {{message}} 104 |
105 | ``` 106 | 107 | 为什么不推荐这样做呢?因为在我们后续会学习应用`filter`或`directive`等功能时,或者将数据在多个`ng-controller`之间共享时,如果不对数据进行二次封装,可能会导致数据互相访问不了的情况。在使用AngularJS的时候,养成数据二次封装的习惯,可以避免很多这样的问题。 108 | -------------------------------------------------------------------------------- /zh/chapter04_4.md: -------------------------------------------------------------------------------- 1 | # 数据绑定data-binding 2 | 上一节我们介绍了如何将`ng-controller`的数据显示在HTML当中,但是我们如何在页面中修改这些数据呢?这一步操作也很简单。 3 | 4 | 我们先直接看看代码吧! 5 | 6 | ```html 7 | 8 | 9 | 10 | 11 | 12 | {{"学习AngularJS 1.x"}} 13 | 14 | 15 | 16 |
17 |

{{data.message + " World!"}}

18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | ``` 27 | 28 | 运行结果 29 | 30 | ![图4-3 ng-controller运行结果](./pic/0403_ng-model.png) 31 | 32 | 如果您实际运行代码,会发现,您每输入/删除一个文字,改动会马上在上方显示出来。这就是数据绑定的魅力! 33 | 34 | ## 功能的绑定 35 | 界面操作里面还有一个重要的功能,就是界面上按钮的与控制器中的函数进行绑定。这个也很容易实现: 36 | 37 | ```javascript 38 | App.controller("FirstCtrl", function($scope){ 39 | $scope.data = { 40 | message : "Hello" 41 | }; 42 | 43 | //在$scope上绑定一个函数 44 | $scope.onClick = function(){ 45 | alert($scope.data.message); 46 | } 47 | }); 48 | ``` 49 | 50 | ```html 51 |
52 |

{{data.message + " World!"}}

53 | 54 | 55 | 56 |
57 | ``` 58 | 59 | 点击按钮,我们即可看到数据通过弹出框显示了出来(`onClick`函数中的逻辑)。 60 | 61 | ![图4-3 ng-click运行结果](./pic/0404_ng-click.png) 62 | 63 | ## 更多地方的绑定 64 | 除了用于显示信息外,数据绑定还可用于其他地方。比如,下面的例子用于根据输入来调整样式: 65 | 66 | ```html 67 | 68 | 69 | 70 | 71 | {{"学习AngularJS 1.x"}} 72 | 88 | 89 | 90 | 91 | 92 |
示例文本(可输入strike bold red)来调整样式
93 | 94 | 95 | 96 | 97 | 98 | ``` 99 | 100 | 运行效果如下: 101 | 102 | ![图4-3-1 ng-click运行结果](./pic/0423.png) 103 | -------------------------------------------------------------------------------- /zh/chapter04_5.md: -------------------------------------------------------------------------------- 1 | # 条件判断 `ng-if` / `ng-show` / `ng-hide` 2 | 本节我们将学习的是如何通过变量来控制HTML是否显示。 3 | 4 | 这三个语句具体的用法如下: 5 | 6 | 在`$scope.data`中添加`flag`变量,设置默认值为`true` 7 | 8 | ```javascript 9 | //app.js 10 | $scope.data = { 11 | message: "Hello", 12 | flag: true 13 | }; 14 | ``` 15 | 16 | 将以下代码放置在FirstCtrl中 17 | 18 | ```html 19 | 通过复选框来控制文字是否显示 20 | 21 | 22 |
23 |

ng-if中的文字

24 |
25 | 26 | 27 |
28 |

ng-show中的文字

29 |
30 | 31 | 32 |
33 |

ng-hide中的文字

34 |
35 | ``` 36 | 37 | 运行结果 38 | 39 | ![图4-5 ng-if为真时界面](./pic/0405_ng-if_true.png) 40 | 41 | ![图4-6 ng-if为假时界面](./pic/0406_ng-if_false.png) 42 | 43 | 从上面的例子可以看出,如果复选框打勾,则界面只显示了前两行文字;而取消复选框的打勾,则显示了最后的一行文字。这个特性可以用于展示界面上的某些信息或者按钮。 44 | 45 | ## `ng-if`与`ng-show`/`ng-hide`的区别 46 | 虽然效果看起来类似,但`ng-if`的工作模式与`ng-show`/`ng-hide`不一样。 47 | 48 | 如果使用`ng-if`来控制元素是否显示,则在不显示的情况下,`ng-if`中包含的内容,会被全部从HTML中移除掉。 49 | 50 | 而如果使用`ng-show`/`ng-hide`,AngularJS只是使用CSS控制将内容隐藏起来。 51 | 52 | 这两者可以应用于不同的场景,如果内容较多,且之后不会使用到,那么可以使用`ng-if`;如果之后还可能会显示出来,那么可以使用`ng-show`/`ng-hide`。 53 | 54 | ## 冒号中的表达式 55 | 例子中使用了`data.flag`直接作为判断依据,但是以上三个标签都支持传入表达式。 56 | 57 | 比如以下的表达式都可以作为冒号中的表达方式: 58 | 59 | ```javascript 60 | data.flag >= 1 61 | data.flag == true 62 | ``` 63 | 64 | 但是请**注意**,在`ng-model`,`ng-if`等标签中传入参数时,是不需要双括号`{{`与`}}`将参数包裹起来的。 65 | -------------------------------------------------------------------------------- /zh/chapter04_6.md: -------------------------------------------------------------------------------- 1 | # 重复语句 `ng-repeat` 2 | 本节将讲述如何使用`ng-repeat`对一个列表的数据进行遍历并显示出来。 3 | 4 | 首先,我们准备如下的数据。这是一个包括三个`object`的`array`。 5 | 6 | ```javascript 7 | $scope.list = [ 8 | { 9 | name: "Harry" 10 | }, 11 | { 12 | name: "Tom" 13 | }, 14 | { 15 | name: "Jerry" 16 | } 17 | ]; 18 | ``` 19 | 20 | 下面,我们将这些数据显示在HTML的一个表格中: 21 | 22 | ```html 23 | 24 | 25 | 26 | 27 |
{{x.name}}
28 | ``` 29 | 30 | 运行结果 31 | 32 | ![图4-7 ng-repeat运行结果](./pic/0407_ng-repeat.png) 33 | 34 | 为了更好的查看具体的运行效果,我们可以查看下最终生成的HTML代码。 35 | 36 | ![图4-8 ng-repeat运行结果(HTML)](./pic/0408_ng-repeat_html.png) 37 | 38 | 从源代码可以看出来,`ng-repeat`直接将其所在的``元素根据`list`的长度复制了3次。并将相应的数据填充了进去。 39 | 40 | ## $index 41 | 在实际的使用场景中,如果我们使用一个表格来管理信息,那么可能表格的每一行都会有一些对应的操作功能(如编辑、删除)等。那么,我们如何在`ng-repeat`中知道是哪一行被点击了呢? 42 | 43 | AngularJS提供了`$index`这个字段让我们实现这个功能。 44 | 45 | 下面,我们来看看使用`$index`的例子: 46 | 47 | 在`app.js`中,对`onClick`函数进行一些改造,让他能够获取传入的数据: 48 | 49 | ```javascript 50 | $scope.onClick = function (index) { 51 | alert("点击了第"+index+"行的按钮"); 52 | }; 53 | ``` 54 | 55 | 将刚才的表格也进行一些改造: 56 | 57 | ```html 58 | 59 | 60 | 61 | 63 | 64 |
{{x.name}}
65 | ``` 66 | 67 | 刷新页面后,让我们点击第一个按钮,效果如下: 68 | 69 | ![图4-8 $index字段应用效果](./pic/0409_ng-repeat_index.png) 70 | 71 | 这样,我们就可以明确的知道用户点击了哪一行了! 72 | 73 | 另外,值得注意的是,`$index`是从`0`开始计算的哟! 74 | -------------------------------------------------------------------------------- /zh/chapter04_7.md: -------------------------------------------------------------------------------- 1 | # 过滤器 `filter` 2 | 过滤器是AngularJS的另一项强大的功能,如果能使用好它,能够帮助我们极大的节省工作量。 3 | 4 | 以下是几个应用`filter`的例子: 5 | 6 | ```javascript 7 | {{ 1234 | number:2 }} 8 | //显示两位小数,结果 1,234.00 9 | 10 | {{ 1234.56 | currency:"人民币¥":0}} 11 | //转化为货币后输出(保留0位小数,四舍五入),结果为 12 | //人民币¥1,234.00 13 | 14 | {{ list | json }} 15 | //将对象转化为json文本输出,结果为 16 | //[ { "name": "Harry" }, { "name": "Tom" }, { "name": "Jerry" } ] 17 | 18 | 19 | //对显示的数据列表按照name进行排序 20 | //结果为显示顺序Harry,Jerry,Tom 21 | ``` 22 | 23 | 以上都是AngularJS的常用用法,具体的系统自带的`filter`的列表,我们可以从[官方网站](https://docs.angularjs.org/api/ng/filter)上获取。这里对管网提供的功能进行一个简要列表: 24 | 25 | Filter名称 | 示例用法 | 说明 26 | :-------: | :----------------------------: | ----------------------------------------------- 27 | filter | - | 传入自定义的函数作为过滤器 28 | currency | currency / currency:"人民币¥":0 | 转化为货币后输出。可选货币单位和保留小数位数。 29 | number | number / number:2 | 将数字转化为文本,自动加逗号。可选设置小数位数。 30 | date | data : format : timezone | 将时间转化到对应的格式和时区 31 | json | json | 将对象转化为Json格式内容输出 32 | lowercase | lowercase | 将文本转化为小写 33 | uppercase | uppercase | 将文本转化为大写 34 | limitTo | limitTo : limit : begin | 截取array从begin位置开始的limit个元素 35 | orderBy | orderBy : expression : reverse | 根据expression的条件对list进行排序,reverse可选,设置为true则反过来排 36 | 37 | ## 多个filter同时应用 38 | AngularJS支持多个filter同时应用,比如以下的例子: 39 | 40 | ```javascript 41 | {{ list | orderBy:'name' | json }} 42 | //对list的内容进行排序后输出成json文本,结果为 43 | //[ { "name": "Harry" }, { "name": "Jerry" }, { "name": "Tom" } ] 44 | ``` 45 | 46 | ## 创建自己的过滤器 47 | 自己创建自定义的过滤器也很简单,我们下面尝试自己制作一个将文字全部翻转过来的过滤器。 48 | 49 | 在`app.js`中增加如下代码: 50 | 51 | ```javascript 52 | //app.js 53 | App.filter("reverse", function(){ 54 | return function(text){ 55 | return text.split("").reverse().join(""); 56 | } 57 | }); 58 | ``` 59 | 60 | 同时,我们利用最早的Hello World的例子,将我们定义的`reverse`这个过滤器应用上去,代码如下: 61 | 62 | ```html 63 |
64 |

{{data.message | reverse}}

65 | 66 |
67 | ``` 68 | 69 | 运行效果: 70 | 71 | ![图4-10 自定义filter的运行效果](./pic/0410_filter.png) 72 | 73 | 如果您期望界面显示的内容进行一些通用的处理,但是又不希望对原本的数据进行改动,那么可以考虑自己制作过滤器! 74 | 75 | ## 通过`filter`进行搜索 76 | AngularJS提供了通过filter的搜索功能。当然,这个搜索功能并不是非常常用,因为搜索工作现在一般在服务端完成。如果数据量非常小(几百行以内),可以考虑使用本功能来筛选结果。 77 | 78 | 示例如下(使用上一节的例子): 79 | 80 | ```javascript 81 | App.controller("FirstCtrl", function ($scope) { 82 | $scope.searchText = ''; 83 | 84 | $scope.list = [ 85 | { 86 | name: "Harry" 87 | }, 88 | { 89 | name: "Tom" 90 | }, 91 | { 92 | name: "Jerry" 93 | } 94 | ]; 95 | }); 96 | ``` 97 | 98 | ```html 99 |
100 | 101 | 102 | 103 | 104 | 105 |
{{x.name}}
106 |
107 | ``` 108 | 109 | 如果我们在输入框中输入T,则列表中只会显示包含T的项目。 110 | 111 | ![图4-10-1 filter用于搜索](./pic/0424.png) 112 | 113 | ### 一些值得注意的用法 114 | 115 | 用法 | 效果 116 | ----------------------------------- | -------------------------------- 117 | `searchText = "T"` | 搜索所有字段 118 | `searchText = {name:"T"}` | 只搜索`name`字段包含`T`的项目 119 | `searchText = {name:"T", last:"H"}` | 搜索`name`字段包含`T`且`last`字段包含`H`的项目 120 | 121 | 对于最后一项,我们可以采取如下输入方法来应用: 122 | 123 | ```html 124 |
125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 |
{{x.name}}{{x.last}}
133 |
134 | ``` 135 | -------------------------------------------------------------------------------- /zh/chapter04_8.md: -------------------------------------------------------------------------------- 1 | # 样式选择器 `ng-class`/`ng-style` 2 | ## `ng-class` 3 | 通过`ng-class`,我们可以对界面元素的css样式进行控制。下面,让我们通过示例来看看功能如何实现: 4 | 5 | > 此示例来源于官网的[ngClass介绍界面](),我进行了一些加工。 6 | 7 | 首先,我们先创建一个`style.css`文件。 8 | 9 | ```css 10 | /* 删除线 */ 11 | .strike { 12 | text-decoration: line-through; 13 | } 14 | 15 | /* 粗体 */ 16 | .bold { 17 | font-weight: bold; 18 | } 19 | 20 | /* 红色 */ 21 | .red { 22 | color: red; 23 | } 24 | 25 | /* 错误 */ 26 | .has-error { 27 | color: red; 28 | background-color: yellow; 29 | } 30 | 31 | /* 橙色 */ 32 | .orange { 33 | color: orange; 34 | } 35 | ``` 36 | 37 | 修改`FirstCtrl`为如下代码: 38 | 39 | ```javascript 40 | //app.js 41 | App.controller("FirstCtrl", function ($scope) { 42 | $scope.data = { 43 | deleted:false, 44 | important:false, 45 | error:false 46 | }; 47 | }); 48 | ``` 49 | 50 | 并在`index.html`的``部分将css文件引入,并加入对应的代码。全部代码如下: 51 | 52 | ```html 53 | 54 | 55 | 56 | 57 | {{"学习AngularJS 1.x"}} 58 | 59 | 60 | 61 | 62 | 63 | 64 |
65 | 66 | 67 |

示例文字

68 | 69 | 选中后上方文字将加上删除线(style中加上strike类)
70 | 71 | 选中后上方文字将变化为粗体(style中加上bold类)
72 | 73 | 选中后上方文字将变红,背景变黄(style中加上has-error类) 74 |
75 | 76 | 77 | 78 | 79 | 80 | ``` 81 | 82 | 运行效果: 83 | 84 | 未选中时效果 85 | 86 | ![图4-11 ngClass运行效果](./pic/0411_ngclass.png) 87 | 88 | 选中第一个的效果 89 | 90 | ![图4-12 ngClass运行效果](./pic/0412_ngclass.png) 91 | 92 | 选中第二个的效果 93 | 94 | ![图4-13 ngClass运行效果](./pic/0413_ngclass.png) 95 | 96 | 选中第三个的效果 97 | 98 | ![图4-14 ngClass运行效果](./pic/0414_ngclass.png) 99 | 100 | 全部选中的效果 101 | 102 | ![图4-15 ngClass运行效果](./pic/0415_ngclass.png) 103 | 104 | ### 动态化的样式输入 105 | 在上方的示例中,我们是针对提前设定好的样式进行是否生效的判断。除了这种使用方式,ng-class还支持直接传入字符串的方式进行样式调整。 106 | 107 | 比如如下示例: 108 | 109 | ```javascript 110 | App.controller("FirstCtrl", function ($scope) { 111 | $scope.data = { 112 | style: "" 113 | }; 114 | }); 115 | ``` 116 | 117 | ```html 118 |
119 |

直接使用字符串作为样式

120 | 121 |
122 | ``` 123 | 124 | 运行效果 125 | 126 | ![图4-16 ngClass运行效果(使用文本作为样式)](./pic/0416_ngclass.png) 127 | 128 | ### 结合两种模式的应用示例 129 | 这两种模式也可以结合使用,示例如下: 130 | 131 | ```html 132 |

同时应用两种样式

133 | ``` 134 | 135 | 此示例可举一反三,比如加入多个文本输入(对应多个来源),以及多个设定好的样式开关。 136 | 137 | > 此示例就不进行具体的运行效果展示了,请读者自行测试效果。 138 | 139 | ### CSS动画效果应用 140 | 我们先在_style.css_中加入css的动画效果代码: 141 | 142 | ```css 143 | .base-class { 144 | transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; 145 | } 146 | 147 | .base-class.animate { 148 | color: red; 149 | font-size:3em; 150 | } 151 | ``` 152 | 153 | 修改HTML代码如下: 154 | 155 | ```html 156 |
157 | 158 |
159 | 160 |
161 | 示例文本 162 |
163 | ``` 164 | 165 | 运行之后,点击上面的按钮,则文字放大变红。点击第二个按钮,则文本变回原来的样子。 166 | 167 | 由于动画效果无法通过截图表示,还请读者自行测试。 168 | 169 | ## `ng-style` 170 | `ng-style`提供的功能比`ng-class`要少一些,只支持样式的传入。我们可以使用以下两种模式: 171 | 172 | ```html 173 | 示例文本 174 | //colorInput为$scope中的对象,传入文本即可 175 | 176 | 示例文本 177 | //styleText为样式为 '{'color':red}'类型的文本 178 | ``` 179 | 180 | 通过样式传入,我们可以直接向元素传入对应的样式,实现样式动态化的效果。 181 | 182 | 一个比较主要的用途是向元素传入动态的背景图片,例子如下(以下两个示例来自于[StackOverflow](http://stackoverflow.com/questions/17252546/angularjs-ng-style-background-image-isnt-working)): 183 | 184 | ```html 185 | data-ng-style="{'background-image':'url(img/products/{{product.img}})'}" 186 | ``` 187 | 188 | 也可以传入一个函数(主要用于解决IE11中背景图片不显示的问题): 189 | 190 | ```html 191 |
192 | 193 | 201 | ``` 202 | 203 | 下面,我们通过官网的[示例](https://docs.angularjs.org/api/ng/directive/ngStyle)来看看如何传入文本: 204 | 205 | ```html 206 | 207 | 208 | 209 |
210 | 示例文本 211 |
当前样式为{{data.myStyle}}
212 | ``` 213 | 214 | 运行效果为: 215 | 216 | ![图4-17 ng-style运行效果](./pic/0417.png) 217 | 218 | 在下一节中,我们还将看到约束为只设置背景颜色的示例。 219 | -------------------------------------------------------------------------------- /zh/chapter04_9.md: -------------------------------------------------------------------------------- 1 | # 下拉列表选项 `ng-options` 2 | 在学习了`ng-repeat`过后,我们其实已经可以用循环的方式实现下拉列表的选项。但是,AngularJS提供了`ng-options`的方法,让我们能够更轻松的完成这项工作。 3 | 4 | 官网提供了一个详尽的[示例](https://docs.angularjs.org/api/ng/directive/ngOptions)进行演示(点击打开后滑动到页面最下部进行效果测试),本节中的内容,是将官网的内容进行梳理后进行的讲解。 5 | 6 | `ng-options`提供了很多功能用来梳理或筛选下拉列表的选项。我们将分别学习它们。 7 | 8 | 首先,让我们学习下如何使用`ng-options`。这里,我们期望实现的是,使用下拉列表,让页面上的一个方块的颜色对应变化: 9 | 10 | 我们首先配置一个颜色的列表,并且在`$scope`中存储一个用于保存选中状态的变量,将它的默认值设置为颜色列表的第一个: 11 | 12 | ```javascript 13 | App.controller("FirstCtrl", function ($scope) { 14 | $scope.colors = [ 15 | {name: '黑色', color:'black' }, 16 | {name: '白色', color:'white' }, 17 | {name: '红色', color:'red' }, 18 | {name: '蓝色', color:'blue' }, 19 | {name: '黄色', color:'yellow'} 20 | ]; 21 | 22 | //保存选中的状态,默认颜色设置为黑色 23 | $scope.colorChosen = $scope.colors[0]; 24 | 25 | }); 26 | ``` 27 | 28 | ```html 29 |
30 | 31 | 36 |
37 | 38 | 当前选中的颜色: {{ colorChosen.name }} 39 |
41 |
42 |
43 | ``` 44 | 45 | 运行页面,我们可以看到下拉列表中有列表中的五种颜色,并且选中不同颜色后,下方方框内的颜色,会根据选择变化。 46 | 47 | ![图4-18 ng-options运行效果](./pic/0418.png) 48 | 49 | 颜色根据选中状态变化,利用到了`ng-model`和`ng-style`的特性。下面,我们将仔细讲解`ng-options`中的语法: 50 | - `color.name` 51 | - 用于显示在下拉框中的名称 52 | 53 | - `for color in colors` 54 | - 类似于ng-repeat中的用法,将colors遍历,每次遍历的对象命名为color 55 | 56 | ## 增加未选中的选项 57 | 在很多时候,我们期望能有一个没选中的选项。我们可以通过手动的方式添加这个选项: 58 | 59 | ```html 60 | 63 | ``` 64 | 65 | ![图4-19 ng-options加上空选项](./pic/0419.png) 66 | 67 | ## 按组排列`group by` 68 | `ng-options`也支持按组排列数据,使用`group by`语法,下面我们看看例子: 69 | 70 | 首先,我们在列表中增加类型字段: 71 | 72 | ```javascript 73 | $scope.colors = [ 74 | {name: '黑色', color: 'black', type: "暗色"}, 75 | {name: '白色', color: 'white', type: "亮色"}, 76 | {name: '红色', color: 'red', type: "暗色"}, 77 | {name: '蓝色', color: 'blue', type: "暗色"}, 78 | {name: '黄色', color: 'yellow', type: "亮色"} 79 | ]; 80 | ``` 81 | 82 | 然后修改ng-options的语法: 83 | 84 | ```html 85 | 113 | ``` 114 | 115 | 运行结果: 116 | 117 | 可以看到,图中的"红色"和"黄色"变为了不可选择的状态。 118 | 119 | ![图4-21 ng-options加上disable when](./pic/0421.png) 120 | 121 | ## 将对象作为参数传入 122 | 在上面的例子中,我们传入的是一个列表`array`。`ng-options`也支持以对象`object`的方式传入数据: 123 | 124 | 使用`object`的方式传入数据,一般是为了简化配置,比如我们采取如下的配置: 125 | 126 | ```javascript 127 | $scope.countries = { 128 | CN: '中国China', 129 | US: '美国United States', 130 | UK: '英国United Kingdom', 131 | GR: '德国Germany' 132 | }; 133 | 134 | $scope.country = 'CN'; 135 | ``` 136 | 137 | 注意,以下代码中,for后面有一个**空格**。如果没有,则无法成功运行!这是因为传入`ng-options`的其实是一串文本,而AngularJS需要解析这段文本,因此提出了对格式的要求。 138 | 139 | ```html 140 |
141 | 142 | 147 |
148 | 149 | 当前选中的国家: {{ country }} 150 |
151 | ``` 152 | 153 | 运行结果,请注意列表中显示的值和选中时变量的值的关系。 154 | 155 | ![图4-22 ng-options传入object作为数据](./pic/0422.png) 156 | -------------------------------------------------------------------------------- /zh/chapter04_summary.md: -------------------------------------------------------------------------------- 1 | # 本章总结 2 | 3 | 在本章中,我们学习了AngularJS的基本用法。掌握了这些用法,相信大家对于AngularJS已经有了基本的了解。 4 | 5 | 我建议您在阅读后续内容之前,对本章内容进行一次回顾,并将印象不深的地方多浏览几遍。如果可能,也请尽量的实际的运行一下示例,修改修改代码,观察具体的运行情况。 6 | -------------------------------------------------------------------------------- /zh/chapter05.md: -------------------------------------------------------------------------------- 1 | # 深入学习AngularJS - Directive 2 | 在前一章中,我们学习了AngularJS的基本用法。从本章开始,我们将学习"深入"一些的部分。 3 | 4 | 本章将介绍AngularJS的Directive。 5 | 6 | > 有若干AngularJS的中文译文将Directive翻译为"指令",但是我感觉此翻译很难让读者明确其具体的含义和用法,因此,我在本书中直接应用了英文名。 7 | 8 | AngularJS的Directive,从实际用途的理解,可以称之为"自定义HTML标签"。举个例子,AngularJS可以让我们进行如下的HTML编码: 9 | 10 | ```html 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 |
19 | ``` 20 | 21 | > 还有一种比较特殊的放置在注释中生效的表达方式,但是我目前没有理解其实现意义,就不在这里介绍了。 22 | 23 | 如果我们预先定义好了针对这些标签的处理方式,那么AngularJS将可以把这些标签自动的转化成HTML显示代码。 24 | 25 | ## Directive在系统中的使用 26 | 其实,Directive作为AngularJS的基本特性,我们已经在前面大量的学习和使用了它。 27 | 28 | 在第四章中我们学习的`ng-app`, `ng-controller`, `ng-model`, ng-if等使用方法。如果您现在再仔细看下它们的使用方法,就会发现它们无一例外的都是Directive! 29 | 30 | ## 学习Directive的路程 31 | 本章我们将从最基本的自定义Directive开始,逐渐深入的学习Directive的特性和高级使用方法。由于Directive的特性主要针对展示界面的操作,目的是对界面操作的抽象与解耦。因此,可能像我一样对前端经验不太足的读者们,可能会对Directive的学习或者使用价值感到困难。因此,学习Directive可能会多花您一些时间,但是相信我,这些付出是非常有价值的! 32 | -------------------------------------------------------------------------------- /zh/chapter05_1.md: -------------------------------------------------------------------------------- 1 | # 制作一个自定义的Directive 2 | 下面我们将制作我们的第一个自定义Directive。让我们对`app.js`和`index.html`进行一些修改: 3 | 4 | ```javascript 5 | //app.js 6 | var App = angular.module("App", []); 7 | 8 | App.directive("people", function(){ 9 | return { 10 | restrict: "E", 11 | template : "

姓名:{{data.name}}

性别:{{data.sex}}

" 12 | } 13 | }); 14 | 15 | App.controller("FirstCtrl", function ($scope) { 16 | $scope.data = { 17 | name: "Harry", 18 | sex : "男" 19 | }; 20 | }); 21 | ``` 22 | 23 | ```html 24 | 25 | 26 | 27 | 28 | {{"学习AngularJS 1.x"}} 29 | 30 | 31 | 32 |
33 | 34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | ``` 42 | 43 | 运行结果: 44 | 45 | ![图5-1 Directive运行效果](./pic/0501_first_directive.png) 46 | 47 | ## 代码分析 48 | 以下这段代码用于声明一个Directive: 49 | 50 | ```javascript 51 | App.directive("people", function(){ 52 | return { 53 | restrict : "E", 54 | template : "

姓名:{{data.name}}

性别:{{data.sex}}

" 55 | } 56 | }); 57 | ``` 58 | 59 | 我们将这段代码分拆开逐步讲解: 60 | 61 | 首先,声明一个Directive的基本结构如下,我们调用了`directive()`函数来告诉AngularJS加入一个新的Directive: 62 | 63 | ```javascript 64 | App.directive(); 65 | ``` 66 | 67 | 调用这个函数,我们需要传入2个参数,第一个参数是Directive的命名(这里是`people`),第二个参数是这个Directive的功能。 68 | 69 | ```javascript 70 | App.directive("people", function(){}); 71 | ``` 72 | 73 | 在实例中,我们直接在第二个参数的函数中返回了一个对象: 74 | 75 | ```javascript 76 | return { 77 | restrict: "E", 78 | template : "

姓名:{{data.name}}

性别:{{data.sex}}

" 79 | } 80 | ``` 81 | 82 | 这个对象中有两个元素,`restrict`和`template`。 83 | 84 | ### `template` 85 | `template`相对比较容易理解,在运行网页时,HTML对应的标签,将被替换成对应的内容。我们这里看看替换后实际的HTML代码如何: 86 | 87 | ![图5-2 Directive生效后的html代码](./pic/0502.png) 88 | 89 | 可以看到,AngularJS在``中间加入了template中的内容。 90 | 91 | #### 用替换而不是插入的方式应用Directive 92 | 如果在配置Directive时,加入`replace : true`(与`restrict`和`template`同级别),则可以让AngularJS用替换的模式应用Directive。 93 | 94 | ```javascript 95 | App.directive("people", function(){ 96 | return { 97 | restrict : "E", 98 | replace : true, 99 | template : "

姓名:{{data.name}}

性别:{{data.sex}}

" 100 | } 101 | }); 102 | ``` 103 | 104 | 具体的效果,是会去除掉` `这对标签。 105 | 106 | ### `restrict` 107 | `restrict`是告诉AngularJS,这个Directive应该如何使用。 108 | 109 | 下面这个表格,总结了restrict可能有的值,具体的每种应用方案,我们将在下一节详解。 110 | 111 | 值 | 对应类型 | 使用方法 112 | --- | --------- | ----------------------------- 113 | E | element | ` ` 114 | A | attribute | `
` 115 | C | class | `
` 116 | EAC | - | 以上三种都可使用 117 | 118 | 如果在restrict中设定了使用方法,而在HTML代码中却未按照对应的方法使用,那么代码将不会生效! 119 | -------------------------------------------------------------------------------- /zh/chapter05_2.md: -------------------------------------------------------------------------------- 1 | # Directive的命名和使用规则 2 | 在前一节中,我们创建了一个名为"people"的Directive。并且通过 ` ` 使用了它。 3 | 4 | 但是,在实际应用场景中,我们的命名通常不止1个单词,这时候我们就需要注意Directive的命名和使用规则。 5 | 6 | 对Directive的命名,AngularJS是有特殊的规则需求的。并且,在JavaScript中的命名,与在HTML对应使用时的名称**不一样**! 7 | 8 | ## 命名规则 9 | AngularJS要求Directive的命名使用**驼峰式**语法,也就是从第二个单词开始,每个单词的首字母大写,并且不使用连接符号。 10 | 11 | 驼峰式命名的例子: 12 | - `people` 13 | - `peopleList` 14 | - `peopleListArray` 15 | 16 | ## 使用规则 17 | 在HTML代码中,使用的是连接符的形式,下面我们对比看看命名和使用的对应字符串: 18 | 19 | 命名 | 使用 20 | ----------------- | ------------------- 21 | `people` | `people` 22 | `peopleList` | `people-list` 23 | `peopleListArray` | `people-list-array` 24 | 25 | 实际使用举例 26 | 27 | ```html 28 | 29 | 30 |
31 | ``` 32 | 33 | ## 为什么会有这种差异 34 | 命名和用法不同的核心原因,是**因为HTML对大小写不敏感,而JavaScript对大小写敏感**。 35 | 36 | 为了保证HTML和JavaScript都能按原有模式正常工作,AngularJS提出了这套解决方法。 37 | 38 | ## 怎么实现的? 39 | AngularJS在解析HTML时,会将名称取出(如`people-list-array`),并进行一下两个方面的处理: 40 | 1. 去除字段的 x- 或 data- 头。(`people-list-array`) 41 | 2. 将字段中的连接符号去除,并将第二个单词开始改为首字母大写,其他字母小写。(`[people,List,Array]`) 42 | 3. 然后合并起来。(`peopleListArray`) 43 | 44 | ### 连接符 45 | 在前面的讲解中,我们讲解示例时,使用的连接符全部都为减号。但实际上,AngularJS支持的连接符有: 46 | 47 | 符号 | 示例 48 | -------- | ------------- 49 | 减号( - ) | `people-list` 50 | 冒号( : ) | `people:list` 51 | 下划线( _ ) | `people_list` 52 | 53 | 但是实际使用中,推荐使用**减号**作为连接符。其他的两种符号,只是因为历史原因提供了支持,但是并不推荐使用。 54 | 55 | ### 为什么要先去除`data-/x-`部分 56 | `data-/x-` 存在的原因是需要符合HTML5标准。如果你使用[HTML5验证器](https://validator.w3.org/nu/#textarea)来验证我们之前的代码,你可能会看到如下结果(黄色背景部分代表不符合标准): 57 | 58 | ![图5-3 HTML5验证结果,无data前缀](./pic/0503.png) 59 | 60 | 而如果我们在ng-app和ng-controller前加上data-前缀,则可以通过HTML5的验证。 61 | 62 | ![图5-4 HTML5验证结果,有data前缀](./pic/0504.png) 63 | 64 | 所以,如果你的项目需要使用HTML5的验证工具,那么就需要在字段前加上data-前缀。 65 | 66 | 另:x-的存在,可能是针对XHTML的支持。 67 | 68 | **注意:**,因为有这个条件存在,因此,请不要给你的Directive起data开头的名字! 69 | -------------------------------------------------------------------------------- /zh/chapter05_3.md: -------------------------------------------------------------------------------- 1 | # 让Directive支持传入数据 2 | 在第一节中,我们使用的Directive,可以直接获取并显示控制器中的数据(人的名称和性别)。但是,如果我们有多个人的信息需要显示怎么处理?这个问题其实非常常见,因为Directive通常是将需要在界面中重复使用的部分抽象出来,便于一次修改,多处地方生效(如博客的评论的列表显示)。 3 | 4 | 如果我们按照现在的代码结构(详见第一节),期望放置不同的人的信息,只能采取重复多个控制器的方式,可能的代码如下: 5 | 6 | ```html 7 | 8 | 9 | 10 | 11 | {{"学习AngularJS 1.x"}} 12 | 13 | 14 | 15 |
16 | 17 | 18 |
19 | 20 |
21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | ``` 31 | 32 | 这样做,无法实现动态化的列表,是无法实现我们期望的功能的。我们理想中的情况应该是什么样子呢?当然是能够并列放置这些Directive,通过传入不同的数据来让Directive展示不同的内容。 33 | 34 | ```html 35 |
36 | 37 |
38 | 39 | 40 |
41 |
42 | ``` 43 | 44 | 这样的功能,可以通过配置Directive的`scope`定义实现。 45 | 46 | ## Directive的`scope` 47 | 在之前学习控制器`ng-controller`的使用过程中,我们使用了`$scope`功能。`$scope`用于提供对接HTML和JavaScript对应模块的功能。 48 | 49 | 而Directive在默认情况下,是没有自动绑定一个`$scope`的。也就是说,在默认情况下,Directive无法在JavaScript中接收传入的数据(因为缺少一个存储信息的载体),形成我们期望的效果。但是,Directive提供了非常简单的定义一个scope的功能: 50 | 51 | ```javascript 52 | App.directive("people", function(){ 53 | return { 54 | restrict: "A", 55 | scope:{ 56 | info: "=" 57 | }, 58 | template : "

姓名:{{info.name}}

性别:{{info.sex}}

" 59 | } 60 | }); 61 | 62 | App.controller("FirstCtrl", function ($scope) { 63 | $scope.harry = { 64 | name: "Harry", 65 | sex : "男" 66 | }; 67 | }); 68 | ``` 69 | 70 | 注意,这里我将restrict从"E"(element元素)改变成为了"A"(attribute 属性),这样它的使用方法有了一些变化: 71 | 72 | ```html 73 |
74 |
75 |
76 | ``` 77 | 78 | 在HTML代码里,我们为div元素配置了一个people的属性和一个info属性;并将FirstCtrl的$scope.harry传入给了info。最终的显示效果如下: 79 | 80 | ![图5-5 传入数据的Directive](./pic/0505.png) 81 | 82 | ## `scope`中的配置 83 | 可以看到,在上方的JavaSciprt文件中,我们对scope的定义使用了如下结构: 84 | 85 | ```javascript 86 | scope:{ 87 | info: "=" 88 | } 89 | ``` 90 | 91 | 首先,`scope:{}`是告诉这个Directive它需要自己存储信息(类似于建立一个基于这个Directive的`$scope`)。 92 | 93 | `info: "="` 这段配置,告诉Directive从HTML标签中,获取名为`info`的属性,并将它的值存储在`scope.info`中。这样,我们就达到了存储数据的效果。 94 | 95 | ### 在一个`ng-ontroller`中放入多个相同的Directive 96 | 下面,我们在`FirstCtrl`中增加几个人的数据,并将它们通过Directive显示出来: 97 | 98 | ```javascript 99 | //在FirstCtrl中加入如下代码 100 | $scope.anotherPerson = { 101 | name : "张三", 102 | sex : "男" 103 | }; 104 | ``` 105 | 106 | ```html 107 |
108 |
109 |
110 |
111 | ``` 112 | 113 | 运行效果如下: 114 | 115 | ![图5-6 在一个控制器中多个Directive](./pic/0506.png) 116 | 117 | ## 通过`ng-repeat`和directive一起显示数据 118 | 知道了如何传入数据,那么我们就可以将Directive的使用和`ng-repeat`结合起来,实现列表显示数据的效果。 119 | 120 | 我们先将`FirstCtrl`的数据变化为一个`array`: 121 | 122 | ```javascript 123 | App.controller("FirstCtrl", function ($scope) { 124 | $scope.people = [ 125 | { 126 | name: "Harry", 127 | sex: "男" 128 | }, 129 | { 130 | name: "张三", 131 | sex: "男" 132 | } 133 | ]; 134 | }); 135 | ``` 136 | 137 | ```html 138 |
139 | 140 |
141 |
142 |
143 | ``` 144 | 145 | 实现的效果与上一张图片一样。(具体的页面HTML代码会有差异,请您自行测试查看) 146 | 147 | ### 在Directive中修改控制器中的数据 148 | 以上我们看到的示例只是将数据显示了出来,如果我们期望在Directive中修改这些数据如何处理呢? 149 | 150 | 其实很简单,将`template`中原先显示的数据的部分,替换为`input`即可。 151 | 152 | ```javascript 153 | App.directive("people", function () { 154 | return { 155 | restrict: "A", 156 | scope: { 157 | info: "=" 158 | }, 159 | template: "

性别:{{info.sex}}

" 160 | } 161 | }); 162 | ``` 163 | 164 | ```html 165 |
166 | {{ peopleList | json}} 167 | 168 |
169 |
170 |
171 | ``` 172 | 173 | 刷新界面后,我们可以在输入框中尝试修改。效果如下: 174 | 175 | ![图5-7 在Directive中修改数据](./pic/0507.png) 176 | 177 | ### 以只读的方式传入数据 178 | 除了以等号`=`直接传入对象之外,Directive也支持直接传入文本,使用`@`符号。 179 | 180 | ```javascript 181 | App.directive("people", function () { 182 | return { 183 | restrict: "A", 184 | scope: { 185 | name: "@", 186 | sex : "@" 187 | }, 188 | template: "

性别:{{sex}}

" 189 | } 190 | }); 191 | ``` 192 | 193 | ```html 194 |
195 | {{ peopleList | json}} 196 | 197 | 198 |
199 |
200 |
201 | ``` 202 | 203 | 运行效果: 204 | 205 | ![图5-8 在Directive中传入字符串](./pic/0508.png) 206 | 207 | 可以看到,我们在Directive中传入的数据进行的数据修改,并未反馈到FirstCtrl中。 208 | 209 | ## 在Directive中进行函数回调 210 | 上面我们介绍了等号`=`和`@`符号的使用方法,它们分别对应传入对象和文本。但是,如果我们期望传入一个回调函数呢?这样我们就可以实现如封装一个按钮为一个Directive,然后让它在点击后实现我们期望的功能的效果。 211 | 212 | 这就需要使用到`&`符号,下面我们来看看实际的例子(这个例子比较复杂,请仔细分析研读): 213 | 214 | ```javascript 215 | var App = angular.module("App", []); 216 | 217 | App.directive("formDirective", function () { 218 | return { 219 | restrict: "A", 220 | scope: { 221 | //这里使用&符号来接受传入的函数 222 | btnClick: "&" 223 | //注意:这里没有加入下方的value模型 224 | }, 225 | template: 226 | //一个用于输入文字的输入框,绑定到value上 227 | "
" + 228 | //提交的按钮,绑定上方scope的btnClick方法 229 | //注意传入参数的方式和HTML中具体使用的方式 230 | "" 231 | } 232 | }); 233 | 234 | App.controller("FirstCtrl", function ($scope) { 235 | $scope.clickBtnCallback = function (msg) { 236 | alert("点击了按钮!信息是:" + msg); 237 | } 238 | }); 239 | ``` 240 | 241 | 对应的HTML代码: 242 | 243 | ```html 244 | 245 | 246 | 247 | 248 | {{"学习AngularJS 1.x"}} 249 | 250 | 251 | 252 |
253 | 254 |
255 |
256 | 257 | 258 | 259 | 260 | 261 | ``` 262 | 263 | 运行结果: 264 | 265 | ![图5-8 在Directive中传入函数和数据回传](./pic/0508.png) 266 | -------------------------------------------------------------------------------- /zh/chapter05_4.md: -------------------------------------------------------------------------------- 1 | # 使用`templateUrl`获取模板 2 | 有些时候,Directive中的模板`template`会变得很大,如果仍然放置在定义中,那么可能会造成阅读和修改不方便的情况。 3 | 4 | 针对这种情况,我们可以将`template`替换为`templateUrl`,通过引入外部文件的形式来调用布局。 5 | 6 | 例如: 7 | 8 | ```javascript 9 | var App = angular.module("App", []); 10 | 11 | App.directive("formDirective", function () { 12 | return { 13 | restrict: "A", 14 | scope: { 15 | }, 16 | templateUrl:"part.html" 17 | } 18 | }); 19 | 20 | App.controller("FirstCtrl", function ($scope) { 21 | 22 | }); 23 | ``` 24 | 25 | ```html 26 | 27 | 28 | 29 | 30 | {{"学习AngularJS 1.x"}} 31 | 32 | 33 | 34 | 35 |
36 |
37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | ``` 45 | 46 | 同时,我们还要加入一个新的html文档。为了演示,我们将新建的文档放置在和index.html同一个目录,命名为part.html: 47 | 48 | ```html 49 |

part.html

50 |

这里是part.html中的内容

51 | ``` 52 | 53 | 运行效果: 54 | 55 | ![图5-10 templateUrl的使用](./pic/0510.png) 56 | 57 | ## `ng-template` 58 | 除了直接将HTML部件存储为独立的文件,我们也可以直接使用AngularJS提供的ng-template功能。这点在第四章中也有提到,这里是一个新的示例,帮助您对比物理文件和`ng-template`文件的优先级。 59 | 60 | 例如: 61 | 62 | ```html 63 | 64 | 65 | 66 | 67 | {{"学习AngularJS 1.x"}} 68 | 69 | 70 | 71 | 72 | 73 | 77 | 78 | 79 |
80 |
81 |
82 | 83 | 84 | 85 | 86 | 87 | ``` 88 | 89 | 这里,我们保留了上个例子中的**所有**文件(包括独立的part.html),对JavaScript也未进行任何修改。 90 | 91 | 运行效果如下: 92 | 93 | ![图5-11 templateUrl的使用](./pic/0511.png) 94 | 95 | 要使用这个功能,我们需要在` 86 | 87 | ``` 88 | 89 | ### 实际体验`element`的功能 90 | 我们在引入jQuery后,可以通过如下代码查看效果: 91 | 92 | > 这里需要注意的是,使用jqLite的方法和以下代码中使用的方法是不一样的,因为jqLite不支持通过标签方式获取子元素。如果您有兴趣学习jqLite的使用方法(并且拥有一定的英文阅读能力),可以在[这里](https://docs.angularjs.org/api/ng/function/angular.element)查看官方文档。 93 | 94 | ```javascript 95 | App.directive("formDirective", function () { 96 | return { 97 | restrict: "A", 98 | template:"

标题

这里是段落文字

", 99 | link: function(scope, element, attrs){ 100 | element.children("h1").addClass("strike"); 101 | } 102 | } 103 | }); 104 | ``` 105 | 106 | ```html 107 |
108 |
109 |
110 | ``` 111 | 112 | ![图5-12 element的使用](./pic/0512.png) 113 | 114 | ### 在`element`上绑定鼠标移入移出时的变化效果 115 | 116 | ```javascript 117 | App.directive("formDirective", function () { 118 | return { 119 | restrict: "A", 120 | template:"

标题

这里是段落文字

", 121 | link: function(scope, element, attrs){ 122 | element.children("h1").bind("mouseenter", function(){ 123 | element.children("h1").addClass("strike"); 124 | element.children("h1").text("鼠标移过来了"); 125 | }); 126 | 127 | element.children("h1").bind("mouseleave", function(){ 128 | element.children("h1").removeClass("strike"); 129 | element.children("h1").text("鼠标移开了"); 130 | }) 131 | } 132 | } 133 | }); 134 | ``` 135 | 136 | 运行时,当鼠标移动到标题上,则标题文字会变化成"鼠标移过来了",并加上删除线效果;当鼠标移开,则文字会变为"鼠标移开了"。 137 | 138 | ![图5-13 element的使用](./pic/0513.png) 139 | 140 | 因为主要是jQuery的用法,更多的实际应用就不在本书中详述了。如果有兴趣学习jQuery,您可以通过上网搜索或者购买书籍的方式来学习。 141 | -------------------------------------------------------------------------------- /zh/chapter05_6.md: -------------------------------------------------------------------------------- 1 | # 把Directive变为一个容器`transclude` 2 | 在前面我们使用到的Directive,都会将包含有Directive的元素整体替换为`template`中的内容。这样,就让Directive的用途缩减为只能封装最低级别的元素。 3 | 4 | 但是我们使用的`ng-app`,`ng-controller`等,也同样都是Directive,而我们可以在这些元素中,直接填入HTML代码。这是如何实现的呢?这就要应用到Directive的`transclude`属性。 5 | 6 | ```javascript 7 | App.directive("formDirective", function () { 8 | return { 9 | restrict: "A", 10 | //通过transclude标签将Directive变为一个容器 11 | transclude: true, 12 | //注意template中的ng-transclude,这里是放置原有代码的地方。 13 | template: "

标题

这里是段落文字

" 14 | } 15 | }); 16 | ``` 17 | 18 | ```html 19 |
20 |
21 |

这段文字是放置在Directive中间的。

22 |
23 |
24 | ``` 25 | 26 | 运行结果: 27 | 28 | ![图5-14 transclude的使用](./pic/0514.png) 29 | 30 | 查看HTML代码如下: 31 | 32 | ![图5-15 transclude的效果HTML](./pic/0515.png) 33 | -------------------------------------------------------------------------------- /zh/chapter05_7.md: -------------------------------------------------------------------------------- 1 | # Directive之间互相通讯 2 | 本节是Directive的高级使用方法之一,通过赋予Directive之间互相通讯的功能,我们可以将部件的抽象化提升到一个更高的层次。 3 | 4 | 本节将通过官方网站中一个较复杂的[例子](https://docs.angularjs.org/guide/directive)来讲解具体的使用方法,通过Directive的配置,将HTML中的代码自动抽取为一个Tab列表,点击Tab列表中的标题,则可自动的显示Tab中包含的内容。 5 | 6 | 在JavaScript代码中,我们声明了2个Directive,`gqTabContainer`和`gqTabContent`。 7 | 8 | `gqTabContainer`中加入了`controller`这项配置,并封装了`panes`用于存储数据,`$scope.select`用于接收界面点击事件,以及一个`addPane`方法用于接收`gqTabContent`的调用。 9 | 10 | `gqTabContent`中加入了`require`这项配置,获取的对象作为第四个参数传入`link()`函数。 11 | 12 | ```javascript 13 | var App = angular.module("App", []); 14 | 15 | App.directive("gqTabContainer", function () { 16 | return { 17 | restrict: 'E', 18 | transclude: true, 19 | scope: {}, 20 | //注意这里为tabContainer增加了一个controller,并引入了$scope 21 | controller: ['$scope', function ($scope) { 22 | var panes = $scope.panes = []; 23 | 24 | //tab列表中项目被选中(点击)的处理函数 25 | $scope.select = function (pane) { 26 | angular.forEach(panes, function (pane) { 27 | pane.selected = false; 28 | }); 29 | pane.selected = true; 30 | }; 31 | 32 | //初始化页面时,供其他Directive调用的注册函数 33 | this.addPane = function (pane) { 34 | if (panes.length === 0) { 35 | $scope.select(pane); 36 | } 37 | panes.push(pane); 38 | }; 39 | }], 40 | //注意templateUrl的命名 41 | templateUrl: "gqTabList" 42 | }; 43 | }); 44 | 45 | App.directive('gqTabContent', function () { 46 | return { 47 | //获取gqTabContainer这个Directive 48 | require: '^gqTabContainer', 49 | restrict: 'E', 50 | transclude: true, 51 | scope: { 52 | title: '@' 53 | }, 54 | //第四个参数是获取到的Directive 55 | link: function (scope, element, attrs, tabContainer) { 56 | //调用了上方gqTabContainer的addPane()方法 57 | //注意参数命名,不需要和上方Directive一致 58 | tabContainer.addPane(scope); 59 | }, 60 | //注意templateUrl的命名 61 | templateUrl: "gqTabContent" 62 | }; 63 | }); 64 | ``` 65 | 66 | 在HTML代码中,我们直接使用了`gq-tab-container`和`gq-tab-content`。 67 | 68 | ```html 69 | 70 | 71 | 72 | 73 | {{"学习AngularJS 1.x"}} 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 |

标题1

85 |

这是第一个标签下的内容

86 |
87 | 88 |

标题2

89 |

这是第二个标签下的内容

90 |
91 |
92 | 93 | 94 | 104 | 105 | 111 | 112 | 113 | 114 | ``` 115 | 116 | 运行效果: 117 | - 当点击"标签1"或"标签2"时,下方会自动展示对应的内容。 118 | 119 | ![图5-16 Directive之间通讯](./pic/0516.png) 120 | -------------------------------------------------------------------------------- /zh/chapter05_summary.md: -------------------------------------------------------------------------------- 1 | # 本章总结 2 | 本章讲述的内容是AngularJS的核心内容之一,并且对于之前前端开发经验不足的读者可能会造成一些学习上的困难。但是我建议各位读者好好的掌握本章的内容,这样在利用AngularJS构建网站时,思路更清晰更有条理。 3 | -------------------------------------------------------------------------------- /zh/other/README.md: -------------------------------------------------------------------------------- 1 | AngularJS的学习记录 2 | ====== 3 | Learning AngularJS 1.x 4 | ------ 5 | 6 | 7 | 本书是我在学习和应用AngularJS 1.x 的过程中,对使用AngularJS制作一个完整的基于html/javascript的B/S网站的过程记录和总结。除去Angular 1.x的相关内容外,我还会记录很多“与Angular无关”的内容,这些内容主要是针对整个B/S体系思考以及技术架构和服务器端编程相关的技术。这些都是我的一些思考和总结,权当给大家的一些参考。 8 | 9 | 在所有内容开始之前,我想先向读者们介绍下我自己和写这本书的原因: 10 | 11 | ## 为什么写这本书 12 | 13 | 写这本书的目的是帮助我自己梳理在AngularJS的学习和实践的过程中的知识点和思路。特意使用gitbook工具整理成成书,是为了给自己一些鞭策的动力,并对学习的成果进行一些总结,与大家分享。 14 | 15 | 可能与很多书的作者不一样,我并不是一名技术的资深人士。我有过几年的C/S后端程序员经验(使用php),并在2015年使用AngularJS 1.3构建了一个网站(后端使用php/mysql),在此之前,我是一名移动互联网的产品经理。在2016年起,我准备构建我之前制作网站的v2.0版本。新版本从需求、功能方面都有了非常大的扩展。因此,我在准备沿用目前技术架构的基础上,期望以更加“地道”的方式来实现整个技术模块。 16 | 17 | 最初选用AngularJS,原因是javascript太难了。在移动互联网产品和php后端的工作经验,让我的思维形成了一些定式,让我在学习javascript和JQuery的过程中困难重重。虽然我之前也使用node.js制作过一些公司内部使用的工具。但是,在制作网站的过程中,DOM/BOM实在是让我焦头烂额。这时候,我发现了AngularJS,这实在让我惊喜莫名,因为我突然知道如何制作前端网站了。因此,在2015年初,我在网络上购买了一套基于AngularJS/BootStrap的前端网站模板,在此基础上完成了网站的第一个版本(修改代码,塞入我需要的功能页面)。 18 | 19 | 以现在的技术发展流程而言,要实现一个产品,可选择的技术和设计模式非常之多。我所提供的,只是在我实践的过程中走通的一条道路。 20 | 21 | 由于我的能力和知识库有限,可能书中很多地方并不符合“最佳实践”(Best Practice)。因此,如果您在阅读本书的过程中,碰到表述或技术上的问题或缺陷,请和我联系。 22 | ``` 23 | 我的联系方式 24 | 25 | 微信/WeChat hharry 26 | 邮箱/Email harry@andtoo.net 27 | ``` 28 | 29 | ## 章节 30 | 31 | ### 第一部分 32 | 在开始编码之前 33 | 设计、构建 34 | 35 | 理解团队里面有哪些角色和哪些人 36 | 37 | 技术选型 38 | 为什么选择B/S 39 | 为什么选择AngularJS 40 | why not angular 2 beta 41 | 为什么选择php/phalcon 42 | 43 | 功能设计 44 | xmind设计功能 45 | axure设计界面 46 | 通讯协议的设计 47 | 48 | 49 | ### 第二部分 50 | AngularJS 的安装 51 | 52 | 我对AngularJS的理解 53 | binding 54 | controller 55 | 命名data.variable 56 | directive 57 | 58 | 59 | 60 | 61 | 62 | ### 第三部分 63 | 64 | $http 65 | $ui-route 66 | single page app 67 | 68 | Angular-material的应用 69 | 70 | 71 | ## 使用的写作工具 72 | * [Atom](https://atom.io/) - 写作本书使用的工具 73 | * [GitHub](https://github.com/) - 本书源代码托管 74 | * [GitBook](http://www.gitbook.com/) - 本书托管网站 75 | 76 | ## 涉及到的相关软件和框架 77 | * [AngularJS](https://angularjs.org/) - 前端JS框架 78 | * [Angular Material](https://material.angularjs.org/latest/) - 前端界面框架 79 | * [PHP](https://www.php.net/) - 服务器端基础语言 80 | * [phalcon](https://phalconphp.com/zh/) - PHP框架 81 | * [MySql Community Server](http://dev.mysql.com/downloads/mysql/) - 数据库软件 82 | * [WebStorm](https://www.jetbrains.com/webstorm/) - 前端工作调试 83 | * [PhpStorm](https://www.jetbrains.com/phpstorm/) - 后端工作调试 84 | * [Ubuntu 14.04 Server](http://www.ubuntu.com/server) - 服务器操作系统 85 | -------------------------------------------------------------------------------- /zh/other/part1/Chapter_1.md: -------------------------------------------------------------------------------- 1 | # 战略分析 2 | 3 | 当你拥有一个产品的思路(idea)了之后,战略分析可以帮助你把这个思路细化,并确认是否有价值,是否可行。目前因为市场发展速度过快(特别是移动互联网的世界),新概念层出不穷(O2O、互联网+)。因此很多人忽视了这一步(或者想的不够细致),直接就开始行动了。诚然,在一个产品的发展过程中,思路可能千变万化,甚至于项目本身的核心都会变化多次。快速的启动后续的工作,至少可以保证在时间上有先发优势。但是,我的建议是保守一点,至少在战略分析的这个阶段,把工作**做细致,做完整**。 4 | 5 | 为什么?因为要尽可能保证最终的成功。最终成功的标准是什么?赚钱! 6 | 7 | 一个新的思路的诞生,通常伴随着一个新的产品和一家新的公司,我们称之为创业。但是创业成功的标准是啥? 8 | 9 | 我列举一个理想中的公司发展模型吧,看您认为在以下哪个阶段可以认为产品/公司成功了: 10 | 11 | 1. 第一阶段 12 | * 产品的核心和方向已经定位明晰 13 | * 团队构建完毕,各方面都有不错的人才 14 | * 团队内部和谐,对于产品的核心和功能上偶有争论,但是大家都在齐心协力的奔着美好的未来进发 15 | * 初期资金来自于创始人自筹或天使投资人,日子过得比较紧,但是很充实 16 | 2. 第二阶段 17 | * 产品原型制作出来并成功上线 18 | * 用户数量增长到几千或数万,并带来了第一笔有收入的交易 19 | * 引入了比较高额的天使投资,公司在目前阶段不缺钱了 20 | 3. 第三阶段 21 | * 产品业务模型稳定,用户数量井喷式发展,用户发展到数百万 22 | * 团队人员急速扩充,增加到近一百人,并引入了管理高层和中层 23 | * 因为高额的推广/运营支出,公司目前还不赚钱,但是拥有一个可预期的高收益回报 24 | * 经过紧张谈判,引入了A轮风投,让公司可以继续快速的成长 25 | 4. 第四阶段 26 | * 产品业务扩展成多产品线,并获得了广大的市场认可 27 | * 公司扩张到500-1000人 28 | * 公司已经能够产生正向营收 29 | * 引入了B/C/D轮投资,公司也在积极筹备上市过程 30 | 5. 第五阶段 31 | * 公司成功上市或者出售给BAT等大型企业 32 | * 公司通过并购、投资方式扩展业务线 33 | 34 | 从这五个比较粗略的阶段划分,其实不是那么容易判断出成功的标准在哪个阶段达到了。那么我们从不同的角度来分析下。 35 | 36 | 从创始人的角度(思路的发起者、公司的创办者),成功的期望是什么?我说一个比较理想的情况,就是达到财务自由。也即是可以马上退休并且之后的日子里不用为钱的事情发愁,还可以活的比较舒服。那这个标准换算应该是多少钱呢?以前我的一位朋友计算过,如果35岁退休,考虑到通货膨胀等因素,那么之后需要2000余万元存款。如果按这个标准计算,公司在第四阶段能够达到这个标准(卖掉公司的话)。 37 | 38 | 当然,这个算法比较极端,我们应该设立一个更合适的标准,公司可以长期体面的运作下去,并能够为你提供比较可观的薪资或红利。此标准可在第三阶段,通过降低公司的发展速度实现。 39 | 40 | 那么,前面两个阶段,公司的创始人能够算作成功吗?如果在以上这个例子里面,大家可能会很容易得出判断。但是,现实生活中呢,我见过层出不穷的如下例子: 41 | 42 | * *我们的目标就是拿到风投* 43 | * *我们的目标是快速的把风投的钱烧光,然后再看看市场情况* 44 | * *上一次的项目因为某某原因失败了,这次我又想了个新点子,希望拿笔钱了开始做* 45 | 46 | 甚至于社会中还存在一个这样的"商业模式",一群人以想出符合天使/风投胃口的项目为核心,以快速的花光获得的投资为己任,“赚投资人的钱”。 47 | 48 | 49 | 50 | 从一个产品的思路到最终的成功,一般需要几年的时间,开始想清楚一些,比不断花钱花时间试错要好。 51 | 52 | 后面会帮你节省更多的时间。 53 | 54 | 创业的目的是什么?其实很简单,两个字,赚钱。创业的最终目的是这家公司的产品能够获得市场认可并长期的运行下去,这样公司的创始人和股东能够获得丰富的经济回报。 55 | 56 | 但是在开始时多想多分析,多花几天的时间去收集更多的信息,将 57 | 58 | 59 | 60 | 61 | 62 | 在见天使投资人/风险投资的时候,他们可能会让你“用一句话说明你到底要做什么”。其实目的就是判断你是否把你的思路的核心提炼出来了,然后再根据他的价值观判断你提炼出来的这个核心,是否有价值,是否值得投资。 63 | 64 | 如果你认为你做的事情非常有创新,将来拥有广阔的市场,那么他们还有三个问题: 65 | 66 | 1. 你做的这个事情是否是世界上的第一个? 67 | 2. 你面向的客户群体究竟有多大? 68 | 3. 如果在你上线运营之后,出现一个仿冒者,他需要花多久做到你现在的发布时的程度? 69 | 70 | 71 | 在启动一个项目之前,这是一个必须做,且必须做好的工作。 72 | -------------------------------------------------------------------------------- /zh/other/part1/Chapter_1_phalcon.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/other/part1/Chapter_1_phalcon.md -------------------------------------------------------------------------------- /zh/other/part1/Part_1_Intro.md: -------------------------------------------------------------------------------- 1 | 第一部分 在开始编码之前 2 | ====== 3 | 4 | ``` 5 | 此部分记述了技术开发前的所有相关工作,如果您只对AngularJS的开发记述感兴趣,可直接跳转到第二部分阅读。 6 | ``` 7 | 8 | 技术是团队的一部分,将一个思路变为最终的产品,首先要经历战略分析、团队组建、功能细化、界面/流程设计的过程,最终才到技术选型/实现阶段。 9 | 10 | 本章主要记述了我在这四方面的一些思考方式和过程。 11 | 12 | 对于一个面向企业的应用而言(本书将涉及到的应用方向),这前面的四个过程的重要度,要高于最终技术方面的工作。因为技术实现在当今的环境下,相对容易达到稳定、安全的标准。但是客户所关心的,是产品本身的核心功能能否带来价值。如果产品的功能本身无法提供足够的价值,技术实现再好也只是一款失败的产品。 13 | 14 | 将技术的优先度放低,除了上述的原因之外,还有很重要的一方面,就是设定了一个前提,这个产品不会面临“高开”。也就是说这个产品的发布,不会伴随着高预算的推广。如果产品在上线之后,有预期会很快铺开大量的用户(比如网游以及重量级大鳄开发的新应用——比如微信),那么本书介绍的技术选型等,将不再适用。 15 | 16 | 举个比较浅显的原因,如果选用了AngularJS,在读取页面时,会载入149KB的AngularJS库(取自AngualrJS 1.5.0-rc.0文件)。在小客户量的情况下,这个文件大小还可以接受;但是当面向客户量大的时候,如每天百万次或千次请求,每天仅获取此JS文件的请求流量就会达到149GB(以百万次计算)。按目前阿里云OSS的收费标准计算,月度流量费仅此文件就会达到七千余元。加上AngularJS构建完整网站所需的其他库(如界面库、ui-route),最终的流量成本很容易超过一名业界较资深的javascript开发人员的成本。因此,在这个情况下,最合适的方案将是招聘专职的javascript架构师,构建属于此应用的专用javascript库,并将容量进行压缩和优化。 17 | 18 | 当然,其他方面的考虑可能更多(如功能的灵活便利性和进一步优化的空间),但是我在这里用计算成本的方式来进行比较,希望大家更容易理解一些(业务的决策者可能更容易理解成本方面的比较)。 19 | 20 | ## 章节内容 21 | ### 第一章 战略分析 22 | ### 第二章 团队组建 23 | ### 第三章 功能细化 24 | ### 第四章 界面/流程设计 25 | -------------------------------------------------------------------------------- /zh/other/part2/Chapter_1.md: -------------------------------------------------------------------------------- 1 | # 技术选型 2 | 3 | ##起因 4 | 在2015年1月1日,我选择了AngularJS 1.x作为我实施新项目的前端开发框架。确定使用AngularJS的主要原因其实很简单,刚好符合我的技术构想而已。 5 | 6 | 我之前的工作经验,并未包含任何的web开发工作,只是单纯的移动互联网C/S结构。而AngularJS满足了我在web端仍然使用此结构制作基于浏览器的客户端。 7 | 8 | ###当时的技术结构 9 | 10 | ``` 11 | 在分析phalcon和AngularJS之前,我想先尽量将其他方面的的内容整理出来。因为这些内容都是我过去工作经历的一些经验。 12 | ``` 13 | 14 | * Web端 15 | * 使用AngularJS构建 16 | * 部署在阿里云OSS上(纯静态html) 17 | * Server端 18 | * 使用Phalcon构建(基于php) 19 | * 部署在阿里云ECS上 20 | * 数据库使用阿里云RDS 21 | * 通讯协议 22 | * 使用http默认方式通讯(使用https加密) 23 | * 使用基于json构建的通讯协议和通讯包 24 | * 源码管理 25 | * 使用gitlab的开源版本 26 | * 部署在独立的阿里云ECS上 27 | * 工具链 28 | * WebStorm 用于web开发 29 | * PhpStorm 用于php开发 30 | * SourceTree 用于源代码管理 31 | * OS X Server 用于本地php运行调试环境 32 | * Chrome 开发者工具调试、网络搜索资料 33 | 34 | ####针对以上技术选型的分析 35 | 36 | 37 | **阿里云 aliyun.com** 38 | 39 | 阿里云目前是我租用网络服务器的首选,因为已经有3年多的使用经验。我总结阿里云的优势如下: 40 | 41 | ``` 42 | 注:以下主要都是根据我2012-2013年时进行服务器部署方案选择时的经验总结而成。由于一直使用阿里云服务且并未遇到不可克服的问题,因此也未再去了解其他的新技术和方案。 43 | ``` 44 | 45 | 1. 快速稳定 46 | * 可快速的按需购买并部署,一般几分钟即可完成整个流程。 47 | * 在整个使用过程中,未出现过网络中断或服务器宕机的问题。 48 | 2. 成本低廉 49 | * 租用阿里云的服务器的成本,相较购买部署实体服务器而言要低很多。从运营角度而言,此成本可忽略不计(对比人力成本)。 50 | 3. 交流方便 51 | * 后台发起工单后阿里云会在几分钟内处理完毕。 52 | * 阿里云工作人员多次上门拜访,并听取了我的意见和建议。 53 | 4. 自动备份 54 | * 数据库的自动备份和回档,让我在运营阶段省心很多。 55 | * 另外在一些核心逻辑和数据出错之后,做紧急回档的效率也比较高。 56 | 5. 支付方便 57 | * 绑定了公司的支付宝账号,直接支付非常便捷。 58 | 59 | 60 | **gitlab** 61 | 62 | 我所在的团队基本都一直使用git作为源码管理工具(早年使用过svn,但很快就切换到了git)。最开始,我们使用的是不带web界面的git服务器系统,然后另外建立了Bug追踪管理系统(如bugfree等)。但团队仍然为git的权限管理头疼。 63 | 64 | 因此,我尝试部署了gitlab系统,之后就一直使用它了。我总结gitlab的优势如下: 65 | 66 | * 简单直观的web界面 67 | * 在gitlab里面浏览项目,和在github上一样简单直观 68 | * 完整且便捷的权限管理 69 | * 可详细的配置各个用户针对各个项目的权限 70 | * 超便捷的issue系统 71 | * 在gitlab里面建立的issue/bug,可以快速指派给其他人 72 | * 这也是我喜欢gitlab的__核心原因__之一,极大提高了技术和测试团队的协作效率 73 | * issue系统支持markdown语言,这也是我在wiki之后真正仔细的学习和使用markdown的地方 74 | * web merge功能 75 | * 在网页上进行merge的对比和确认(此项工作让代码review变成了真正可操作且必操作的任务) 76 | * web hook功能 77 | * 通过此项功能,我们实现了针对公网运营服务器的一次性统一自动升级功能 78 | 79 | 当然,gitlab也有他的缺陷所在,就是部署它需要的硬件实在是太高了。由于gitlab使用ruby & rails制作,官网上当时推荐的运行环境要求是8-16GB内存。根据我的尝试,在1-2GB内存的服务器上,编译安装会很困难,即使安装成功,运行一段时间后,也会出现gitlab进程挂掉的情况。但是在4GB内存的阿里云服务器上,gitlab可以稳定运行。 80 | 81 | ``` 82 | 小窍门:部署好gitlab之后,这台服务器仍然可以挪作他用,比如跑php的测试环境之类的。不会影响到gitlab的稳定运行。 83 | ``` 84 | 85 | 86 | **通讯协议** 87 | 88 | 使用http是因为实现最为便捷,并可利用nginx,php-fpm等的优化,以及阿里云的负载均衡等服务,快速的横向扩展,来提高架构的承载能力。 89 | 90 | 包体结构使用的非常基础的设计: 91 | 92 | ```json 93 | 访问包体 Request: 94 | { 95 | "c":"controller", //controller名称 96 | "a":"action", //action行为名称 97 | "s":"session", //访问session 98 | "d":{ 99 | //data_package 上传数据 100 | } 101 | } 102 | 103 | 回复包体 Response: 104 | { 105 | "c":200, //返回码,200=ok 106 | "d":{ 107 | //data_package 返回数据 if(c==200) 108 | }, 109 | "m":{ 110 | //错误信息 if(c!=200) 111 | } 112 | } 113 | ``` 114 | 115 | 从目前角度而言,网络服务的包体结构设计满足需求即可。其他方面的考量(如包体大小等),已经不足以成为影响包体结构设计的因素。 116 | -------------------------------------------------------------------------------- /zh/pic/0201_create_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0201_create_project.png -------------------------------------------------------------------------------- /zh/pic/0202_empty_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0202_empty_project.png -------------------------------------------------------------------------------- /zh/pic/0203_terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0203_terminal.png -------------------------------------------------------------------------------- /zh/pic/0204_bower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0204_bower.png -------------------------------------------------------------------------------- /zh/pic/0301_install_angular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0301_install_angular.png -------------------------------------------------------------------------------- /zh/pic/0302_run_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0302_run_index.png -------------------------------------------------------------------------------- /zh/pic/0303_hello_world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0303_hello_world.png -------------------------------------------------------------------------------- /zh/pic/0401_ng-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0401_ng-app.png -------------------------------------------------------------------------------- /zh/pic/0402_ng-controller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0402_ng-controller.png -------------------------------------------------------------------------------- /zh/pic/0403_ng-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0403_ng-model.png -------------------------------------------------------------------------------- /zh/pic/0404_ng-click.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0404_ng-click.png -------------------------------------------------------------------------------- /zh/pic/0405_ng-if_true.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0405_ng-if_true.png -------------------------------------------------------------------------------- /zh/pic/0406_ng-if_false.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0406_ng-if_false.png -------------------------------------------------------------------------------- /zh/pic/0407_ng-repeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0407_ng-repeat.png -------------------------------------------------------------------------------- /zh/pic/0408_ng-repeat_html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0408_ng-repeat_html.png -------------------------------------------------------------------------------- /zh/pic/0409_ng-repeat_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0409_ng-repeat_index.png -------------------------------------------------------------------------------- /zh/pic/0410_filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0410_filter.png -------------------------------------------------------------------------------- /zh/pic/0411_ngclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0411_ngclass.png -------------------------------------------------------------------------------- /zh/pic/0412_ngclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0412_ngclass.png -------------------------------------------------------------------------------- /zh/pic/0413_ngclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0413_ngclass.png -------------------------------------------------------------------------------- /zh/pic/0414_ngclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0414_ngclass.png -------------------------------------------------------------------------------- /zh/pic/0415_ngclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0415_ngclass.png -------------------------------------------------------------------------------- /zh/pic/0416_ngclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0416_ngclass.png -------------------------------------------------------------------------------- /zh/pic/0417.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0417.png -------------------------------------------------------------------------------- /zh/pic/0418.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0418.png -------------------------------------------------------------------------------- /zh/pic/0419.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0419.png -------------------------------------------------------------------------------- /zh/pic/0420.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0420.png -------------------------------------------------------------------------------- /zh/pic/0421.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0421.png -------------------------------------------------------------------------------- /zh/pic/0422.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0422.png -------------------------------------------------------------------------------- /zh/pic/0423.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0423.png -------------------------------------------------------------------------------- /zh/pic/0424.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0424.png -------------------------------------------------------------------------------- /zh/pic/0501_first_directive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0501_first_directive.png -------------------------------------------------------------------------------- /zh/pic/0502.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0502.png -------------------------------------------------------------------------------- /zh/pic/0503.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0503.png -------------------------------------------------------------------------------- /zh/pic/0504.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0504.png -------------------------------------------------------------------------------- /zh/pic/0505.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0505.png -------------------------------------------------------------------------------- /zh/pic/0506.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0506.png -------------------------------------------------------------------------------- /zh/pic/0507.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0507.png -------------------------------------------------------------------------------- /zh/pic/0508.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0508.png -------------------------------------------------------------------------------- /zh/pic/0509.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0509.png -------------------------------------------------------------------------------- /zh/pic/0510.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0510.png -------------------------------------------------------------------------------- /zh/pic/0511.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0511.png -------------------------------------------------------------------------------- /zh/pic/0512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0512.png -------------------------------------------------------------------------------- /zh/pic/0513.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0513.png -------------------------------------------------------------------------------- /zh/pic/0514.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0514.png -------------------------------------------------------------------------------- /zh/pic/0515.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0515.png -------------------------------------------------------------------------------- /zh/pic/0516.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hairui219/learning_angular/f33045d9734d9d5f968d4206be2d7584da4bfc66/zh/pic/0516.png --------------------------------------------------------------------------------