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

0 0
原创粉丝点击