AngularJS学习笔记(一)
来源:互联网 发布:程序员种类 编辑:程序博客网 时间:2024/04/29 01:06
前言
几个月之前了解过一点Angular,主要是通过phonecat应用程序了解一些入门东西,但是当被问及什么是Angular或者你对Angular的理解时,只记得一个MVVM双向数据绑定,显然这是不能令人满意的。现在重新来过吧。
ps:该文档只是见证自己学习Angular的过程。所用版本为1.4.3。另外向大家推荐个windows下各 API离线查找工具Velocity,官网:http://velocity.silverlakesoftware.com/,真的不是一般地好用。
AngularJS简介
AngularJS是一个为动态WEB应用设计的结构框架,创新点在于,利用数据绑定和依赖注入,使你不用再写大量的代码。AngularJS的一些出众之处在于:
- 构建一个CRUD应用可能用到的全部内容包括:数据绑定、基本模板标识符、表单验证、路由、深度链接、组件重用、依赖注入
- 测试方面包括:单元测试、端到端测试、模拟和自动化则是框架
- 具有目录布局和测试脚本的种子应用作为起点
而Angular信奉的是,当组建视图同时又要写软件逻辑时,声明式的代码会比命令式的代码好的多。
基本概念
首先举个例子:
<!doctype html><html lang="en" ng-app="myApp"><head> <meta charset="UTF-8"> <title>myApp</title> <style> #test { width: 100px; height: 100px; background-color: red; border: 1px solid #ccc; } </style> <script src="js/jquery-1.7.1.js"></script> <script src="js/angular.min.js"></script></head><body ng-controller="myCtrl"> <div id="test" ng-click="click()">Come ON!</div> <p>{{width}} * {{height}}</p> <p>Width: <input type="text" ng-model="width"/></p> <p>Height: <input type="text" ng-model="height"/></p> <script> "use strict"; var myApp = angular.module("myApp", []); myApp.controller('myCtrl', ['$scope', function($scope) { var oDiv = angular.element('#test'); $scope.width = oDiv.width(); $scope.height = oDiv.height(); $scope.click = function() { $scope.width = parseInt($scope.width) + 10; $scope.height = parseInt($scope.height) + 10; }; $scope.$watch('width', function(to, from) { oDiv.width(to); }); $scope.$watch('height', function(to, from) { oDiv.height(to); }); }]); </script></body></html>
从代码中可以看出,在HTML中引入了一些以ng开头的标记,这些就是angular(一下简称ng)声明式的代码。
- 使用ng-app声明ng的初始化工作,同时定义了ng应用的作用域,ng的初始化一般绑定在DOMContentLoaded事件中,可以使用
angular.bootstap(element,modules,config);
手动引导ng应用程序。 - ng-controller声明控制器,控制器里可以写相应的代码逻辑,修改相应的$scope,进行model到view的数据绑定工作。
- ng-click绑定click事件,事件在controller中声明,绑定到$scope.
- ng模板解析:默认使用
{{}}
- ng-model:ng的双向数据绑定声明
依赖注入
ng通过在函数参数中做手脚来完成“依赖声明”的功能。['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {}]
像AMD声明一样,该函数依赖于$scope,dep1,dep2,然后依次作为参数传递进去。也可以使用另外一种声明方式,利用ng中的函数隐藏属性$inject(不推荐):
var MyController = function($scope, greeter) {}MyController.$inject = ['$scope', 'greeter'];someModule.controller('MyController', MyController);
在处理时,ng通过函数对象的toString()方法将该函数定义的代码转为字符串表现形式,然后利用正则表达式过滤出相应的参数,通过参数名获取资源,最后把资源作为参数调用定义的函数。
因此最好采用上述两种方法来显示声明所需的依赖,防止代码压缩过程中压缩相应的函数参数而报错。
作用域
每个ng应用都有一个根作用域($rootScope),有多个子作用域。因为一些指令会声明新的子作用域,这些作用域的结构关系和其绑定到相应的DOM结构是对应的。
属性查找:当ng查找某个模板中的某个数据时,会按照作用域链一直向上查找,直至找到或查至根作用域$rootrScope为至(独立作用域除外)。
<body ng-controller="parentCtrl"> <div ng-controller="childCtrl"> <p>hello {{name || "world"}}!</p> </div></body>
事件冒泡:我们可以在scopes上模拟DOM事件类型的事件冒泡,该事件可以被广播到子作用域或者触发到父作用域。
<div ng-controller="EventController"> Root scope <tt>MyEvent</tt> count: {{count}} <ul> <li ng-repeat="i in [1]" ng-controller="EventController"> <button ng-click="$emit('MyEvent')">$emit('MyEvent')</button> <button ng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button> <br> Middle scope <tt>MyEvent</tt> count: {{count}} <ul> <li ng-repeat="item in [1, 2]" ng-controller="EventController"> Leaf scope <tt>MyEvent</tt> count: {{count}} </li> </ul> </li> </ul></div> <script> angular.module('myApp', []) .controller('EventController', ['$scope', function($scope) { $scope.count = 0; $scope.$on('MyEvent', function() { $scope.count++; }); }]); </script>
另外,我们还可以调用$watch()
检测某个属性改变。
模板与数据绑定
ng中的主要特点之一就是双向数据绑定。
数据->模板:
可以直接使用ng的默认模板标记{{name}}
,则可以直接绑定一个作用域内的变量。当然也可以更改使用自定义的标记//name//
<script> myApp.config(function($interpolateProvider) { $interpolateProvider.startSymbol('//'); $interpolateProvider.endSymbol('//'); });</script>
模板:
ng有自己的一套强大的模板命令:
1.ng-include直接引入模板内容 <div ng-include="'template.html'"></div>
ng-include内容必须是字符串,需多加个引号。
template.html主要有两种定义方式:
(1)script标签中定义:type属性值为“text/ng-template”,id为ng-include属性值
<script type="text/ng-template" id="template.html"> <p>This is the content of the template</p></script>
(2)外部html文件中定义:该html文件名为ng-include的属性值
Content of template.html
2.内容控制:
(1)ng-cloak
该指令绑定内容不显示,直到ng解析相关指令后才显示解析后的内容,避免相关内容解析前后出现跳转现象。
(2)ng-show/ng-hide
根据表达式的值来改变绑定该命令的DOM的display属性,相关CSS类已经在ng文件中提前定义,且使用了!important
提升权重。
点我: <input type="checkbox" ng-model="checked"><div> 显示: <div ng-show="checked"> 选中时显示。 </div></div><div> 隐藏: <div ng-hide="checked"> 选中时隐藏。 </div></div>
(3)ng-if
不同于ng-show改变DOM的display属性来显示隐藏节点,ng-if根据表达式的布尔值判断:false则从文档中移除该DOM节点,true则向文档中添加该DOM节点。
(4)ng-switch
根据值的匹配情况来显示相应的节点:
ng-init直接在模板中进行赋值,与作用域无关。
<div ng-init="a=1"> <div ng-switch on="a"> <div ng-switch-when="1">1</div> <div ng-switch-when="2">2</div> <div ng-switch-default>other</div> </div> </div>
(5)ng-repeat
遍历对象或数组:
<div ng-init="list = [{name: 'AAA'}, {name: 'BBB'}, {name: 'CCC'}]"> <ul ng-repeat="member in list"> <li>{{$index}}</li> <li>{{$first}}</li> <li>{{$middle}}</li> <li>{{$last}}</li> <li>{{$odd}}</li> <li>{{$even}}</li> <li>{{member.name}}</li> </ul> </div>
额外变量:
$index 当前索引
$first 是否为首元素
$middle 是否为中间元素
$last 是否为尾元素
$odd 当前索引是否为奇数
$even 当前索引是否为偶数
遍历对象使用(key, value) in obj.
另外,默认待遍历的数组中不能有重复值,因为数组元素与相应的DOM元素是一对一的关系。如需要使用:
<ul ng-repeat="n in [10,10,10,10] track by $index"> {{n}} </ul>
(6)其它
- ng-src src属性
- ng-href href属性
- ng-checked 选中状态
- ng-selected 被选择状态
- ng-disabled 禁用状态
- ng-multiple 多选状态
- ng-readonly 只读状态
3.样式
(1)ng-style
使用对象字面量的形式来赋值:
<input type="button" value="set color" ng-click="myStyle={color:'red'}"><input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}"><input type="button" value="clear" ng-click="myStyle={}"><br/><span ng-style="myStyle">Sample Text</span><pre>myStyle={{myStyle}}</pre>
(2)ng-class
直接通过字符串绑定CSS中预定义的类
<!doctype html><html lang="en" ng-app><head> <meta charset="UTF-8"> <title>Document</title> <script src="js/angular.min.js"></script> <style> .strike { text-decoration: line-through; } .bold { font-weight: bold; } .red { color: red; } </style></head><body><p ng-class="style">Using String Syntax</p><input type="text" ng-model="style" placeholder="Type: bold strike red" aria-label="Type: bold strike red"></body></html>
4.事件绑定:
模板中的事件绑定预定义了一些常用的事件绑定指令,可以直接传递相关的处理程序且直观地在DOM中声明。
- ng-blur
- ng-change
- ng-click
- ng-dblclick
- ng-focus
- ng-keydown
- ng-keypress
- ng-keyup
- ng-mousedown
- ng-mouseenter
- ng-mouseleave
- ng-mousemove
- ng-mouseover
- ng-mouseup
使用$event可以给相应的事件处理函数传递事件对象本身
<input ng-keyup="show($event)"> <p>event keyCode: {{ keyCode }}</p> <p>event altKey: {{ altKey }}</p> <script> angular.module('myApp',[]) .controller('myCtrl', function($scope) { $scope.show = function($event) { $scope.keyCode = $event.keyCode; $scope.altKey = $event.altKey; } }); </script>
5.表单
HTML中form是一个核心控件,是网页与用户进行交流的主要方式之一。而ng对form进行了封装”ng-form”,区别是HTML中的form不能嵌套,而ng-form可以嵌套。而ng-form的目的就是为了统一控制,而不是为了取代form标签。
form中的一些控件可以预先通过ng-controller中的$scope绑定一些状态。
<!doctype html><html lang="en" ng-app="myApp"><head> <meta charset="UTF-8"> <title>Document</title> <script src="js/angular.min.js"></script></head><script> angular.module('myApp', []) .controller('FormController', ['$scope', function($scope) { $scope.userType = 'guest'; }]);</script><style> .my-form { -webkit-transition:all linear 0.5s; transition:all linear 0.5s; background: transparent; } .my-form.ng-invalid { background: red; }</style><body><form name="myForm" ng-controller="FormController" class="my-form"> userType: <input name="input" ng-model="userType" required > <span class="error" ng-show="myForm.input.$error.required">Required!</span><br> age: <input name="input_b" ng-model="age" required pattern="\d+"> <span class="error" ng-show="myForm.input_b.$error.required">Required!</span> <span class="error" ng-show="myForm.input_b.$error.pattern">Pattern!</span><br> <code>userType = {{userType}}</code><br> <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br> <code>myForm.input.$error = {{myForm.input.$error}}</code><br> <code>myForm.$valid = {{myForm.$valid}}</code><br> <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br></form></body></html>
ng给form提前定义了一些CSS类:
- ng-valid 当表单验证全部通过时使用
- ng-invalid 表单中有未通过验证的控件时使用
- ng-pristine 当表单为被修改之前使用
- ng-dirty 当表单被修改之后使用
- ng-submitted 当表单被提交之后使用
form对象有一些属性:
- $pristine 表单是否未被动过
- $dirty 表单是否被动过
- $valid 表单是否通过验证
- $invalid 表单是否未通过验证
- $error 表单的错误对象
其中$error是一个hash对象,引用表单控件中未通过验证的键值对。属性是验证失败信息,值是对应的实例列表。另外,该失败对象是按一定的验证逻辑所取,例如上例中的age输入框,先判定required,在判定pattern。$error对象可能的属性有:email/max/maxlength/min/minlength/number/pattern/required/url/date/time/week/month.
同时,我们也能在form中的具体某个input框中查看相应的错误,格式为formName.inputName.$error
.但是,input控件的相关属性是ng-required/ng-pattern等,经测试发现,仅ng-maxlength,ng-max,ng-min与HTML5中相关属性有区别:ng-maxlength=’12’可以输入超过12个字符,但超过相关属性为true,而maxlength则最多只能输入12个字符,超过默认丢弃,相关错误属性永不为true.
(1)checkbox/radio
可以为checkbox分别绑定ng-true-value/ng-false-value的值,为radio绑定value值。而这些值与视图中的相关控件是否选中相对应。
checkbox: <input type="checkbox" name="box" ng-model="check" ng-true-value="'China'" ng-false-value="'Beijing'" /> <span>check = {{check}}</span> <hr /> radio: <input type="radio" name="checkRadio" ng-model="checkRadio" value="China" /> radio: <input type="radio" name="checkRadio" ng-model="checkRadio" value="Beijing" /><br> <span>radio = {{checkRadio}}</span>
(2)textarea
包含input框中相应属性,仅多了ng-trim指令。
(3)select
select控件中,有个用于呈现下拉选项的指令ng-options
主要用于select模板中绑定的是非字符串。主要用法见下例:
<!doctype html><html lang="en" ng-app="myApp"><head> <meta charset="UTF-8"> <title>Document</title> <script src="js/angular.min.js"></script></head><body> <div ng-controller="myCtrl"> <h3>参数是数组情况下:</h3> <label>Color (可以指定value为null的option) <select ng-model="myColor1" ng-options="color.name for color in colors"> <option value="">——Choose Color——</option> </select> <span>选择颜色:{{myColor1}}</span> </label><br /> <label>Color(区分显示和值) <select ng-model="myColor2" ng-options="color.name as color.shade for color in colors"> </select> <span>选择颜色:{{myColor2}}</span> </label><br /> <label>Color(以shade值分组) <select ng-model="myColor3" ng-options="color.name group by color.shade for color in colors"> </select> <span>选择颜色:{{myColor3}}</span> </label><br /> <label>Color (以shade分组,且有附加条件) <select ng-model="myColor4" ng-options="color.name group by color.shade disable when color.notAnOption for color in colors"> </select> <span>选择颜色:{{myColor4}}</span> </label> <h3>参数是对象情况下:</h3> <label>Color (以shade分组,且有附加条件) <select ng-model="ordinalNumber1" ng-options="value.name for (key, value) in ordinal"> </select> <span>所选列:{{ordinalNumber1}}</span> </label><br /> <label>Color(区分显示和值) <select ng-model="ordinalNumber2" ng-options="value.value as value.name for (key, value) in ordinal"> </select> <span>所选列:{{ordinalNumber2}}</span> </label><br /> <label>Color(以shade值分组) <select ng-model="ordinalNumber3" ng-options="value.name group by value.group for (key, value) in ordinal"> </select> <span>所选列:{{ordinalNumber3}}</span> </label><br /> <label>Color (以shade分组,且有附加条件) <select ng-model="ordinalNumber4" ng-options="value.value group by value.group disable when value.notAnOption for (key, value) in ordinal"> </select> <span>所选列:{{ordinalNumber4}}</span> </label> </div> <script> angular.module('myApp', []).controller('myCtrl', ['$scope', function($scope) { $scope.colors = [ {name:'black', shade:'dark'}, {name:'white', shade:'light', notAnOption: true}, {name:'red', shade:'dark'}, {name:'blue', shade:'dark', notAnOption: true}, {name:'yellow', shade:'light', notAnOption: false} ]; $scope.ordinal = { first: { name: "1st", value: "NO.1", group: "1-3" }, second: { name: "2nd", value: "NO.2", group: "1-3", notAnOption: true }, third: { name: "3nd", value: "NO.3", group: "1-3", notAnOption: true }, fourth: { name: "4th", value: "NO.4", group: "4-5" }, fifth: { name: "5th", value: "NO.5", group: "4-5", notAnOption: false } }; }]); </script></body></html>
通常情况下,ng-repeat也可用在option元素中,但ng-repeat会为每个遍历的实例创造一个新的作用域,而使用ng-options则具有节省内存,响应更快捷的优点。
模板->数据:
ng中模板到数据的绑定主要是通过ng-model来实现。
<p>hello {{name || "World"}}!</p><hr/><input type="text" ng-model="name"/>
当我们在input框中输入内容,会发现模板中内容也相应改变。实际上,ng中的双向数据绑定主要是通过ng-model来实现。
过滤
ng默认提供了一些可以直接使用的过滤指令
- currency 货币过滤指令
- date 时间过滤指令
- filter 数组过滤指令
- json 将js对象转换为json字符串
- limitTo 截取字符串/数组/数字的一部分
- lowercase 字符串转小写
- number 格式化数字
- orderBy 数组排序
- uppercase 字符串转大写
- linky 找出文本输入中的连接然后格式化
模板中使用
我们可以在模板中使用过滤命令,使用方法类似与linux系统中的管道命令{{expression | filter1:arg1:arg2:... | filter2:arg}}
即我们可以在一个语句后面使用多个过滤命令,依次用”|”分割开即可,也可以在一个过滤命令后面传递多个参数,依次用“:”分割开即可。
<span>{{1437272917693 | date:"MM/dd/yyyy 'at' h:mma"}}</span><br><span>{{ ["AAAAA","AAAA","AAA","AA","A","BBB","BB"] | filter:'A' | limitTo: 2 }}</span><br>
JS中使用
JS中使用过滤命令有两种方式:
(1)<filterName>Filter
方式:
在依赖声明中明确声明需要使用filterName的过滤指令,然后就可以在内部向该指令函数传递参数,返回处理后的数据:
angular.module('myApp', []).controller('filterCtrl', ['filterFilter', 'dateFilter', 'numberFilter', 'currencyFilter', '$scope', function(myFilter, dateFilter, numberFilter, currencyFilter, $scope) { $scope.array = contacts; $scope.filteredArray = myFilter(this.array, 'a'); $scope.date = dateFilter(1437272917693, 'mediumDate'); $scope.number = numberFilter(1437272917693,2); $scope.money = currencyFilter(100.1234,'¥',2); }]);
(2)$filter方式
依赖声明中引入$filter,然后我们就可以在内部向该函数传入我们想要使用的过滤指令名,返回对应的过滤指令函数。较方式1简单:
angular.module('myApp', []) .controller('myCtrl', ['$scope', '$filter', function($scope, $filter) { $scope.filteredText = $filter('uppercase')('China'); $scope.number = $filter('number')(123456789.1123); }]);
自定义过滤命令
如果感觉ng默认提供的几种过滤指令满足不了需求,我们可以自定义指令。通过你的module中的filter工厂函数就可以自定义一个新的指令。
angular.module('myApp', []) .filter('reverse', function() { return function(input, uppercase) { input = input || ''; var out = ""; for (var i = 0; i < input.length; i++) { out = input.charAt(i) + out; } // 可传入参数uppercase if (uppercase) { out = out.toUpperCase(); } return out; }; })
向filter工厂函数传入命令名,初始化函数,返回一个过滤函数,过滤函数第一个参数是待过滤的内容,其余参数依次输入。仅当该过滤指令的输入内容改变时,ng才会执行该指令。
另外,自定义的过滤函数应该全部是无状态的,那些有状态的指令无法被ng优化,经常导致表现问题。而如果真的需要维持状态的过滤命令,可指定该过滤函数的$stateful属性,这样每次模板中内容改变该过滤函数都会执行一次。
angular.module('myStatefulFilterApp', []).filter('decorate', ['decoration', function(decoration) { function decorateFilter(input) { return decoration.symbol + input + decoration.symbol; } decorateFilter.$stateful = true; return decorateFilter;}])
另外,自定义的过滤函数只能在模板中使用。
AJAX
与其它框架一样,ng也提供了类似的一套AJAX封装,内部通过XMLHttpRequest对象或JSONP方式。
$HTTP
$HTTP提供基本的操作服务,传入一个config配置对象,设置一些参数,返回一个可以注册成功、失败回调函数的promise对象。$http常用的配置有:
- method 请求方法
- url 请求路径
- params GET请求的参数
- data 请求报文(POST请求的参数)
- headers 定义请求报头
- cache GET请求的缓存
- timeout 过期时间
- responseType 响应类型
另外对于一些请求方式,有一些简写:
- $http.get(url, [config])
- $http.delete(url, [config])
- $http.head(url, [config])
- $http.jsonp(url, [config])
- $http.post(url, data, [config])
- $http.put(url, data, [config])
$http({method: $scope.method, url: $scope.url}). success(function(data, status) { $scope.status = status; $scope.data = data; }). error(function(data, status) { $scope.data = data || "Request failed"; $scope.status = status; });
$http属性:
- pendingRequests 当前请求队列状态,主要用于测试
- defaults 请求的全局配置
异步回调
ng的异步回调函数服务$q为AJAX的异步回调提供服务。
(1)$q用法
- $q(resolveFn, errorFn) 注册并返回一个promise对象
- $q.defer() 返回一个deferred实例
- $q.reject(reason) 包装一个错误
- $q.when(value) 返回一个promise对象
- $q.resolve(value) 与when方法一样,为了与ES6保持一致性
- $q.all(promises) 将多个promise对象合并成一个promise对象
(2)deferred对象:通过$q.defer()构建
- resolve(value) 成功回调
- reject(reason) 失败回调
- notify(value) 更新promise的执行状态
- promise属性 返回一个promise对象
(3)promise
- then(successCallback, errorCallback, notifyCallback) 分别注册成功,失败,通知的回调函数
- catch(errorCallback) 相当于then(null, errorCallback) 注册失败回调函数
- finally(callback, notifyCallback)
angular.module('myApp', []).controller('myCtrl', ['$q', function($q) { function success(message) { console.log("OK! " + message); } function error(message) { console.log("error! " + message); } function notify(message) { console.log('notify! ' + message); } var defer = $q.defer(), promise = defer.promise; promise.then(success, error, notify);// defer.resolve('resolve');// defer.reject('reject'); defer.notify('notify');
其它部分,明天继续。。。
参考内容
http://www.zouyesheng.com/angular.html
http://www.cnblogs.com/lcllao/archive/2012/10/18/2728787.html
- angularjs学习笔记一
- AngularJS学习笔记(一)
- AngularJS学习笔记一
- AngularJS的学习笔记(一)
- AngularJS学习笔记(一)
- AngularJS 学习笔记(一)
- AngularJS学习笔记(一)
- AngularJS学习笔记(一)
- AngularJs学习笔记(一)
- angularjs学习笔记(一)
- AngularJS学习笔记(一)
- AngularJS 学习笔记(一)
- AngularJs学习笔记(一)初认识AngularJs
- AngularJS学习笔记(一)基本配置
- AngularJS --app.js 学习笔记(一)
- Pro AngularJS学习笔记(一)
- Angularjs 学习笔记(一)基础
- angularjs学习笔记一——了解angularjs、开发环境搭建、第一个angularjs程序
- 第一天测试文章
- Android的onCreateOptionsMenu()创建菜单Menu详解
- [黑马程序员](第6-9天)面向对象(上)
- pyinstaller将ico图标等资源打包到exe中的方法
- Failed to fetch URL http://dl-ssl.google.com************
- AngularJS学习笔记(一)
- 12天学好C语言——记录我的C语言学习之路(Day 10)
- zx2000 HDMI audio
- 使用Redis来实现LBS的应用
- 简易版桶排序
- tomcat7配置用户的一点问题
- unity3d边缘发光效果
- 判断字符串是否为数字的多种方法
- C/C++ typedef用法