写在最前:由于 ng 的表达式和博客有冲突,所以除了代码块之外所有的大括号经过了 \
转义!
Angular 介绍
什么是框架和库
库是由开发人员主动使用库里面提供的 API,完成代码功能逻辑
框架里面提供了各种各样的库,这些库可以调用使用,也可以由框架去调用使用
什么是 AngularJS
- 一款非常优秀的前端高级 JavaScript 框架
- 可以轻松构建 SPA 应用程序
- 通过 指令 扩展了 HTML,通过 表达式 绑定数据到 HTML
- 最大程度上解放了 DOM 操作
- 构建更加动感的 HTML 应用程序
AngularJS是为了克服HTML在构建应用上的不足而设计的。AngularJS有着诸多特性,最为核心的是:
- MVC
- 模块化
- 自动化双向数据绑定
- 语义化标签、依赖注入等等
为什么使用 Angular
以前我们是这样的:
|
|
以后将会是这样的:
|
|
AngularJS 优缺点
优点:
- AngularJS 模板功能强大丰富,自带了极其丰富的angular指令。
- AngularJS 是完全可扩展的,与其他库的兼容效果很好,每一个功能可以修改或更换,以满足开发者独特的开发流程和功能的需求。
- AngularJS 是一个比较完善的前端MVC框架,包含服务,模板,数据双向绑定,模块化,路由,过滤器,依赖注入等所有功能;
- AngularJS 是互联网巨人谷歌开发,这也意味着他有一个坚实的基础和社区支持。
缺点:
- AngularJS 强约束导致学习成本较高,对前端不友好。但遵守 AngularJS 的约定时,生产力会很高,对 后台服务器开发程序员友好。
- AngularJS 不利于 SEO,因为所有内容都是动态获取并渲染生成的,搜索引擎没法爬取。
- AngularJS 作为 MVVM 框架,因为实现了数据的双向绑定,对于大数组、复杂对象会存在性能问题。
AngularJS 使用场景
- 单页面应用程序
- 复杂的后台管理系统
- CRUD(增加 Create、查询 Retrieve、更新 Update、删除 Delete)
- 繁杂的 DOM 操作处理的页面
Angular 是一个类 MVC 类结构的 JavaScript 框架,建议构建 CRUD 类型应用的时候使用它,而对于那些图形编辑、游戏开发等应用,使用 Angular 就不如调用其它 JavaScript 类库方便,如 jQuery。
AngularJS资源
- 官方文档:https://docs.angularjs.org/api
- AngularJS 中文社区:http://angularjs.cn/
SPA 单页面应用程序
SPA全称:Single Page Application
,单页面应用程序。
所谓的单页应用:其实就是利用 hash 做网页内部局部内容的替换
(1). 为什么不适用传统的路径?
原因是传统的路径会默认发同步请求跳转
(2). 为什么 hash 中的路径都是以 / 开头
原因是为了区分普通的 hash
传统的网站模型:多页面应用模型
SPA 网站模型
- 网易云音乐实例解析
锚点:网页内部定位
id
a.name
利用锚点改变网页内容
- window对象的
hashchange
事件 window.location
拿到锚点的内容- 根据不同的
hash
显示不同的内容
单页应用的好处
- 提高了整个应用程序的响应速度、增加了用户体验
- 重用资源
- 方便统一控制和代码重用
如何在网页中解析 URL 地址
- http://www.baidu.com/a/b/c?foo=bar&name=jack#/abc
- 字符串操作
- 正则匹配
- a DOM 元素解析
Angular 的应用
关于版本
安装
- github
https://github.com/angular/angular.js/releases
- CDN
https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js
- bower
bower install angular#1.5.8
- npm
npm install angular@1.5.8
第一个 Angular 程序
|
|
代码解析
- 当网页加载完毕,AngularJS 自动开始执行
- HTML 页面中
ng-xxx
的属性称之为指令(Directive) ng-app
指令告诉 AngularJS ,<body>
元素是 AngularJS 应用程序管理的边界ng-init
指令初始化 AngularJS 应用程序变量ng-model
指令把文本框的value
值绑定到变量name
上\{\{ name \}\}
表达式就是把应用程序变量name
绑定到某个元素的innerHTML
ng 使用过程
(0). 引包
(1). 在 body 上添加一个属性:ng-app
(2). 在 body 中写一个 <h1>\{\{'Hello ' + 'World!'\}\}</h1>
解析过程:
- 浏览器从上到下依次解析 DOM 文档
- 当浏览器解析到 body 上有一个 ng-app 属性的时候,浏览器对于不识别的属性会选择忽略
- 当浏览器解析到
<h1>\{\{'Hello ' + 'World!'\}\}</h1>
,浏览器无法识别里面的双花括号以及里面的内容,浏览器会把它当成普通的字符串进行渲染 - 当浏览西发现 script 标签指定的 angular.js 引用文件的时候,发送请求下载该文件
- 当 angular.js 程序下载成功之后,开始自动执行
- ng 自动找到网页中具有 ng-app 属性的元素,然后开始解析该元素内部所有能被 ng 所识别的元素,也就是说 ng-app 在这里就充当了 ng 应用程序启动的入口标识,同时也是 ng 应用程序的管理边界
- ng 找到入口标识之后,开始解析该入口标识中所有的自己能识别的内容
例如,这里使用了一个 \{\{\}\}
表达式,\{\{\}\}
在 ng 中被称作花括号插值表达式。
AngularJS 表达式
- AngularJS 表达式写在双大括号内:
\{\{ expression \}\}
- AngularJS 表达式把数据绑定到 HTML,与
ng-bind
指令基本一致 - AngularJS 将在表达式书写的位置”输出”数据
- 数字
- 字符串
- 对象
- 数组
- AngularJS 表达式 很像 JavaScript 表达式:它们可以包含字符串、操作符和变量
- 与 JavaScript 表达式不同,AngularJS 表达式可以写在 HTML 中
- 与 JavaScript 表达式不同,AngularJS 表达式不支持条件判断,循环及异常
- 与 JavaScript 表达式不同,AngularJS 表达式支持过滤器
在AngularJS中,表达式是一种类似于模板引擎的语,可以在书写的位置 “输出” 数据。
基本使用
- 表达式写在双大括号内:
\{\{ expression \}\}
- 表达式 很像 JavaScript 表达式
- 它们可以包含文字、运算符和变量
- 如
\{\{ 5 + 5 \}\}
或\{\{ firstName + lastName \}\}
支持的类型及操作符
- 数字
- 字符串
- 对象
- 数组
+ - * /
- 三目表达式
- 短路运算符
如果是 null 或 undefined ,表达式不会报错。
Angular 表达式与 JavaScript 区别:
相同点:
都可以包含字母、操作符、变量
不同点:
- AngularJS 表达式可以写在 HTML 中
- AngularJS 表达式不支持条件判断,循环及异常
- AngularJS 表达式支持过滤器
解决表达式闪烁的问题
ng 默认是在 document onload 的时候开始解析执行,ng 在启动执行的时候会自动向 head 中插入一个 style 样式。
- ng-cloak
- ng-bind
详细说明:
解决表达式闪烁方式有两种:
第一种方式:
将 ng 脚本引入到 head 中,ng 官方推荐将 ng 脚本引入最上面;
在所有使用了表达式的外部的节点上加一个属性 ng-cloak;
当加上 ng-cloak 属性的时候,ng 不会等待 DOM onload 执行结束就会先在加了 ng-cloak 的地方作用一个样式 display: none !important;
当 ng 解析完毕之后,ng-cloak(样式) 被自动移除。
第二种方式:
在所有使用表达式的地方都通过 ng-bind 指令来代替;
也就是说使用了 ng-bind 可以完全替代表达式;
用了它就可以解决将 ng脚本引入底部也不闪烁的问题。
AngularJS 指令
AngularJS 指令是以 ng-
作为前缀的 HTML 属性,AngularJS 通过内置的指令来为应用添加功能,AngularJS 同时允许自定义指令,从而构建更加超动感的 HTML。
HTML5 允许扩展的(自制的)属性,以 data-
开头。AngularJS 属性以 ng- 开头,但是也可以使用 data-ng-
来让网页对 HTML5 有效。
指令的使用形式
- ng-xxx 的属性本身并不是标准中定义的属性
- 很多情况下无法通过语法校验
- HTML5 允许扩展的属性,以
data-
开头 - 在 ng 中可以使用
data-ng-
作为前缀来让网页对 HTML5 有效 - 二者效果相同
内置指令
AngularJS 内置了很多指令,用来增强 HTML,以下是一些常用内置指令的介绍。
ngApp
- ng-app
ngController
ngInit
|
|
ngBind
- ng-bind
- ng-non-bindable
ngBindHtml
|
|
ngRepeat
- ng-repeat
|
|
解决重复项报错问题
ngClass
- ng-class
- ng-class-even
- ng-class-odd
|
|
ng-cloak
ng-hide-show-if-switch
|
|
ng-if-hide-show 的区别
- ng-if 是直接就不渲染这个 DOM 了
- 当为 true 的时候直接渲染
- 当为 false 的时候直接移除该元素
- ng-hide/ng-show
- 两者无论是 true 还是 false 元素都在,是通过样式来控制的
ng-src
所有需要动态指定 src 的地方都通过 ng-src 来替换,否则浏览器会真的对这个 src 发起请求
其它常用指令
- ng-checked : 单选/复选是否选中,只是单向绑定数据
- ng-disabled : 是否禁用
- ng-readonly : 是否只读
- ng-selected : 是否选中,只是单向数据绑定
事件型指令
- ng-click :鼠标单击
- ng-blur :失去焦点
- ng-focus :得到焦点
- ng-change :发生改变
- ng-copy :拷贝完成
- ng-dblclick :鼠标双击
- ng-submit:表单提交
- ng-copy
- ng-cut
- ng-paste
- ng-keydown
- ng-keyup
- ng-mousedown
- ng-mouseenter
- ng-mouseleave
- ng-mouseover
- ng-mouseup
|
|
ng 中也提供了一些单向数据绑定的指令
也就是说只能通过模型获取到数据,但是不能通过改变元素值而影响视图模型数据。
视图数据模型:$scope
- $scope 是用来视图和数据之间的胶水、粘合剂
- 视图和控制器之间的数据桥梁
- 用于在视图和控制器之间传递数据
- 用来暴露数据模型(数据、行为)
- 监视模型数据的变化,做出相应的动作
$scope.$watch
如何设计 $scope
根据原型抽象数据和行为:
- 数据
- 行为
ViewModel
ng 官方把自己定义为一个 MVC 框架。很多开发使用者把它称之为 MVVM 框架。
- $scope 实际上就是 MVVM 中所谓的 VM(视图模型)
- 正式因为 $scope 在 ng 中大量使用甚至盖过了 c 的概念,所以很多人把 ng 称之为 mvvm 框架
数据模型作用域
把所有的根据视图抽象出来的成员都放到一个控制器函数中也就是都放到到一个 $scoep 中,绝对没有问题,但是这么做,可维护性太差了,毫不相干的业务都放到一起了。所以就可以为不同的业务视图划分不同的作用域,根据不同的业务划分不同的控制器函数,得到对应的 $scope 作用域数据模型对象,不同的作用域作用于不同的视图访问不同的数据和行为,作用域可以嵌套,可以访问嵌套关系的作用域成员。
ng 1.5 以下版本使用视图数据模型定义过程:
- 引包
- 定义全局控制器函数
- 主要目的就是为了把逻辑写到 JavaScript 代码中
- 其次是为了拿到那个 $scope 数据模型对象
- 然后通过操作 $scoep 数据模型,和视图作交互
- 根据视图暴露模型数据成员
- 给 $scope 初始化一些数据成员
- 同时暴露一些行为函数
- 设置入口标识 ng-app
- 设置控制器
- 目的就是为了让你的视图和 $scope 建立作用关系
- 通过操作 $scope 和视图交互
- 把以前对 DOM 的操作变成对 $scope 数据模型对象的操作
- 设置控制器
在 ng 1.5 之后,就不允许定义全局控制器函数了
控制器:Controller
- ng 中的控制器用来对 scope 进行操作
- 包括初始化数据和定义事件响应函数等
- ng 用来解耦业务逻辑层和视图层的关键
- controller 操作 scope,View 则展现 scope 的内容
- 传统前端程序中大量复杂的 DOM 操作逻辑都被转变成对 scope 的操作
定义控制器的三种方式
定义控制器可以有三种方式,注意第一种已经被淘汰。
第一种:传统方式,使用全局函数定义控制器:
|
|
第二种:挂载在某个模块下
|
|
第三种:最正确的方式
|
|
控制器定义例子:
|
|
如何划分控制器
一个页面中,按照不同的功能业务划分不同的控制器。
模块:Module
- 模块定义了一个应用程序
- 模块是应用程序中不同部分的容器
- 模块是应用控制器的容器
- 控制器通常属于一个模块
ng 中模块的引入最重要的目的就是为了解决原来全局定义的控制器污染的问题,还有一个目的就是让我们以模块的形式划分架构。
可以通过
angular.module()
方法操作模块
注意:该方法只有在传入两个参数时才会创建模块,否则为获取已有模块
定义模块
定义一个模块:
|
|
获取已有模块:
|
|
定义依赖别的模块的模块:
|
|
定义模块和控制器(利用模块定义控制器)
- 定义一个模块
angular.module('模块名', [])
- 如果是一个参数,就表示获取一个模块
- 如果两个参数,第二个参数就必须是一个数组
- 这个数组表示该模块的依赖,空数组表示没有任何依赖,同时创建该模块
- 如果有依赖,在数组中指定依赖的模块名即可
- 在该模块下去定义控制器
- 将模块和控制器作用到视图
如何划分模块
加载多个模块
angular.bootstrap(document, ['demo'])
angular.module('MainModule', ['Module1', 'Module2', 'Module3'[,ModuleName]])
模块例子:
|
|
过滤器:Filter
内置过滤器
- currency
- number
- date
- json
- uppercase
- lowercase
- orderBy
- limitTo
- filter
自定义过滤器
|
|
服务:Service
在 Angular 中,服务的概念和后台的服务概念基本是一样的,差别只是在于技术细节。
服务是对公共代码的抽象,比如,如果在多个控制器中都出现了相似的代码,那么把它们提取出来,封装成一个服务,在可维护性方面获得提升。
然而,在工程实践中,引入服务的主要目的是为了优化代码结构,而不是复用。复用只是一项结果,而不是目标。
Angular 调试
将 $scope 模型对象挂载给 window
不推荐使用,麻烦
Chrome 插件:AngularJS Batarang
- 安装插件
基本使用:
- 以 http 协议访问你要调试的页面
- 打开控制台,找到 AngularJS
- 选择 Enable 启用调试
- 切换到 Scope 选项卡
MVVM
M: Model
M: 数据模型
V
V: 视图
VM
ViewModel: 视图模型
C
用来处理视图模型和视图的交互的
使用 ng 总结
- AngularJS 最大程度上减少了页面上的 DOM 操作
- 让开发人员更专注于业务操作
- 通过简洁的指令结合页面结构与逻辑数据
- 通过自定义指令实现组件化编程
- 代码结构更合理
- 维护成本更低
- AngularJS 解放了传统 JavaScript 中频繁的 DOM 操作