AngularJS入门

介绍

AngularJS是Google的员工Miško Hevery在2009年着手开发,
2012年发布1.0版本的一个用javascript写的工具.
使用 属性 (比如 ng-show) 和 表达式 (比如 {{name}}) 扩展了html,
可以方便地构建单一页面应用程序(SPAs:Single Page Applications).
为此,angularjs几乎包办了页面上的所有成分

  • 作为html内容(比如循环输出一个表格)
  • 作为javascript内容(比如定义一个两数相加的函数,然后使用)
  • 作为css(比如预定义一些css(style),在email验证失败的时候不用style=""定义,自动变红色)

抽象概念

AngularJS的抽象使用了MVC,MVVM相同的理念.
html页面作为view,
在页面中使用形如 ng-model 的指令将页面上数据绑定到viewmodel,
在controller中操作viewmodel中的数据.
然后在页面上使用形如 {{}}` 的表达式将处理结果显示回页面. ### 依赖注入 angular积极使用依赖注入(传递的对象是定义好的函数)的方式来定义对象. 比如

1
app.controller('myCtrl', function($scope, CaleService) {...});
- controller `myCtrl` 注入了 `app` - 前者是controller的名称,后者是其内容. 调用时则可以直接使用名称 `myCtrl`,而不是字符串 `"myCtrl"`. - `$scope`, `CaleService` 注入了controller的 `function` ## hello world
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>

<div ng-app="">
<p>名字 : <input type="text" ng-model="name"></p>
<h1>Hello {{name}}</h1>
</div>

</body>
</html>
- 使用 `` 来引入AngularJS. 通常建议放在body的底部以提高加载的速度(脚本后加载). - `ng-app` 声明这该div的范围内是app的范围,model中的变量在范围内可用.这种形式称为指令 - `ng-model` 声明后面的 `name` 称为model的一部分. - `{{name}}
则将model中的数据显示在view中,这种形式称为表达式

主要成分(指令另外参考)

指令

形如 ng-show 等,都是指令.
用于实现各种功能

  • 页面上的元素与model中的变量绑定
  • 显示或隐藏元素
  • 重复元素
  • 定义下拉框内容
  • 定义新的标签等

html5使用 data- 扩展了html,
而AngularJS选择使用 ng-.

  1. TODO ng-app

    此处有些混乱,一般是作为app的名字,
    但在实现特殊功能时需要使用指定的名字.
    在网页加载完毕后自动开始初始化应用程序.

  2. ng-init

    初始化变量,一般不用.
    通常使用controller或特殊的module来定义.

    1
    2
    3
    <div ng-app="" ng-init="firstName='John'">
    <p>初始化变量的内容是: {{ firstName }}</p>
    </div>
  3. ng-controller

    直接定义app所用的controller

    1
    2
    3
    4
    5
    <div ng-app="myApp" ng-controller="myCtrl">
    ...
    </div>
    <script src="myApp.js"></script>
    <script src="myCtrl.js"></script>

    其中
    myApp.js为

    1
    var app = angular.module("myApp", []);

    myCtrl.js为

    1
    2
    3
    4
    app.controller("myCtrl", function($scope) {
    $scope.firstName = "John";
    $scope.lastName= "Doe";
    });

    不过还是要使用app.controller为app添加controller,
    不使用ng-controller可能效果也能实现.

  4. ng-model

    声明该标签的值存入绑定至model.
    在定义模型后,可以对绑定的变量进行验证.
    (尽管例子中使用name来定义和调用,但实测没有ng-model的定义,验证不会生效)
    验证会搭配html页面中的元素生效.

  5. ng-repeat

    常和列表或表格或下拉框搭配使用,
    指定时可以使用in语法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <div ng-app="" ng-init="names=[
    {name:'Jani',country:'Norway'},
    {name:'Hege',country:'Sweden'},
    {name:'Kai',country:'Denmark'}]">
    list:
    <ul>
    <li ng-repeat=" x in names">
    {{ x.name + ', ' + x.country }}
    </li>
    </ul>

    </div>

    表格

    1
    2
    3
    4
    5
    6
    <table>
    <tr ng-repeat="x in names | orderBy : 'Country'">
    <td>{{ x.Name }}</td>
    <td>{{ x.Country | uppercase }}</td>
    </tr>
    </table>

    另外

  6. ng-options

    多用在下拉框中.

    1
    2
    3
    4
    5
    6
    7
    <div ng-app="myApp" ng-controller="myCtrl"> 
    <select ng-model="selectedSite" ng-options="x.site for x in sites"></select>

    <h1>你选择的是: {{selectedSite.site}}</h1>
    <p>网址为: {{selectedSite.url}}</p>

    </div>

    可以获取整个对象,可以输出x对象下的所有成员.

    也可以使用 ng-repeat 实现

    1
    2
    3
    4
    5
    <select ng-model="selectedSite">
    <option ng-repeat="x in sites" value="{{x.url}}">{{x.site}}</option>
    </select>

    <h1>你选择的是: {{selectedSite}}</h1>

    但此处显示 x.site, 值使用 x.url,
    在获取到选择的值后不能使用 x.site

    ng-option 也可以模拟 ng-repeat 中只保留一个值的功能

    1
    2
    3
    4
    <select ng-model="selectedSite" ng-options="x for (x, y) in sites">
    </select>

    <h1>你选择的值是: {{selectedSite}}</h1>
    • 此处显示的是x,而selectedSite无论显示什么,都保存y的部分
  7. ng-disabled

    若变量为true则控件变为disabled

    1
    <button ng-disabled="mySwitch">点我!</button>
  8. ng-show

    若变量为true则显示

    1
    2
    <p ng-show="true">我是可见的。</p>
    <p ng-show="false">我是不可见的。</p>
  9. ng-hide

    若变量为true则隐藏

    1
    2
    <p ng-hide="true">我是不可见的。</p>
    <p ng-hide="false">我是可见的。</p>
  10. ng-if

    前面的 ng-showng-hide 在不可见时仍然存在于html中,
    可以在检查元素时看到.
    ng-if 变量为false时不加入html元素,检查元素也看不到.

  11. ng-click

    定义按钮被按下时调用的函数

    1
    <button ng-click="toggle()">隐藏/显示</button>
  12. ng-include

    包含一个其他文件

    1
    2
    <div ng-include="'runoob.htm'"></div>
    <div ng-include="'https://c.runoob.com/runoobtest/angular_include.php'"></div>
  13. 自定义指令

    这样导致指令不一定使用ng开头.
    命名上,在定义时使用驼峰式命名,
    在调用时使用中间有短线式.(驼峰大写处断开)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <body ng-app="myApp">
    <!-- 此处为调用方法之一 -->
    <runoob-directive></runoob-directive>
    <script>
    var app = angular.module("myApp", []);
    app.directive("runoobDirective", function() {
    return {
    <!-- 定义可以调用的方法,默认值为EA -->
    restrict : "A",
    <!-- 此处使用template制作一个字符串构成的html元素,此外还有templateUrl等 -->
    template : "<h1>自定义指令!</h1>"
    };
    });
    </script>
    </body>
    1. 调用方法

      1. 标签(E)

        1
        <runoob-directive></runoob-directive>
      2. 属性(A)

        1
        <div runoob-directive></div>
      3. 类名©

        1
        <div class="runoob-directive"></div>
      4. 注释(M)

        1
        <!-- directive: runoob-directive -->

表达式

形如 {{name}},
是表达式,专用于把model中的数据显示在页面上.
表达式中可以写表达式.比如

  • {{ 5 + 5 }} 计算数字
  • {{ quantity * cost }} 计算变量中的数字
  • {{ "tahta" + " " + cost}} 字符串相加
  • {{person.name}} 取字典中的内容
  • {{array[2]}} 取数组中的内容

{{name}} 与指令 ng-bind="name" 效果相同.
表达式的使用受到作用域的限制.

辅助成分

过滤器

指令和表达式中都能使用.
以管道命令的形式使用.

  1. 表达式中使用

    1
    <p>姓名为 {{ lastName | uppercase }}</p>

    此外还有

    • lowercase
    • currency
  2. 指令中使用

    1
    2
    3
    4
    5
    <ul>
    <li ng-repeat="x in names | filter:test | orderBy:'country'">
    {{ (x.name | uppercase) + ', ' + x.country }}
    </li>
    </ul>
    • filter 表示匹配字符串
    • orderBy 表示按某个键排序
  3. 自定义过滤器

    定义

    1
    2
    3
    4
    5
    6
    7
    var app = angular.module('myApp', []);

    app.filter('reverse', function() { //可以注入依赖
    return function(text) {
    return text.split("").reverse().join("");
    }
    });

    注意使用了 字符串函数名 + 匿名函数

    使用

    1
    2
    3
    <div ng-app="myApp">
    姓名: {{ msg | reverse }}
    </div>

服务(内建函数)

$scope 表示模型本身一样,
其他使用 $ 符号定义的也都表示特殊含义

  1. $location

    获取当前页面的url地址

    1
    2
    3
    4
    var app = angular.module('myApp', []);
    app.controller('customersCtrl', function($scope, $location) {
    $scope.myUrl = $location.absUrl();
    });

    尽管原生的javascript中也可以通过 window.location 对应,
    但比 window.location 在对低级浏览器上的兼容性更好一些.

  2. $http

    用于发起http请求,并执行回调函数以响应response.
    举例如下

    1
    2
    3
    4
    5
    app.controller('myCtrl', function($scope, $http) {
    $http.get("welcome.htm").then(function (response) {
    $scope.myWelcome = response.data;
    });
    });
    • 注意在使用之前需要先作为一个参数传入controller
    1. 标准的用法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      // 简单的 GET 请求,可以改为 POST
      $http({
      method: 'GET',
      url: '/someUrl'
      }).then(function successCallback(response) {
      // 请求成功执行代码
      }, function errorCallback(response) {
      // 请求失败执行代码
      });
    2. 简写的用法

      1
      2
      $http.get('/someUrl', config).then(successCallback, errorCallback);
      $http.post('/someUrl', data, config).then(successCallback, errorCallback);
      • 复杂一些的项目可能将 posturl 的部分放在其他文件(比如前台的路由)中定义,
        controller中仅仅用构造 datasuccessCallback
    3. 方法一览

      • $http.get
      • $http.head
      • $http.post
      • $http.put
      • $http.delete
      • $http.jsonp
      • $http.patch
  3. $timeout

    用于延时执行任务,单位ms

    1
    2
    3
    $timeout(function () {
    $scope.myHeader = "How are you today?";
    }, 2000);
    • 同样需要作为参数传入controller
  4. $interval

    每隔一段时间执行服务,单位ms

    1
    2
    3
    $interval(function () {
    $scope.theTime = new Date().toLocaleTimeString();
    }, 1000);
  5. $index

    用在表格等循环结构中,表示序号

    1
    2
    3
    4
    5
    6
    7
    <table>
    <tr ng-repeat="x in names">
    <td>{{ $index + 1 }}</td>
    <td>{{ x.Name }}</td>
    <td>{{ x.Country }}</td>
    </tr>
    </table>
  6. $even和$odd

    多表示循环结构中行数的奇偶

    1
    2
    3
    4
    5
    6
    7
    8
    <table>
    <tr ng-repeat="x in names">
    <td ng-if="$odd" style="background-color:#f1f1f1">{{ x.Name }}</td>
    <td ng-if="$even">{{ x.Name }}</td>
    <td ng-if="$odd" style="background-color:#f1f1f1">{{ x.Country }}</td>
    <td ng-if="$even">{{ x.Country }}</td>
    </tr>
    </table>
  7. 自定义服务

    定义

    1
    2
    3
    4
    5
    app.service('hexafy', function() {
    this.myFunc = function (x) {
    return x.toString(16);
    }
    });

    使用

    1
    2
    3
    app.controller('myCtrl', function($scope, hexafy) {
    $scope.hex = hexafy.myFunc(255);
    });

    其他例子

    1
    2
    3
    4
    5
    app.filter('myFormat',['hexafy', function(hexafy) {
    return function(x) {
    return hexafy.myFunc(x);
    };
    }]);
    1
    2
    3
    <ul>
    <li ng-repeat="x in counts">{{x | myFormat}}</li>
    </ul>

全局API

有些功能和过滤器重复,不知道高版本的angularjs会不会改善

  1. angular.$$lowercase()
    **** angular.$$uppercase()

  2. angular.isString()

  3. angular.isNumber()

MVC与controller,scope

  • ng-model 负责从view到model
  • controller负责设置model(设置页面上元素的值,控制开关等.)
    • 在另外有其他语言的后台程序的项目中,
      可以在AngularJS的controller中发起http请求以获取数据等.
  • {{}} 负责model到view

AngularJS会在js中定义controller的内容,
controller定义在一个名为module的容器中,
可以使用依赖注入的方式为容器定义成员
内部可放入value,constant,controller,filter,service,directive,factory等

添加一个控制器

先获取一个module对象,
然后为module对象添加controller.
分别指定名字和函数行为即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div ng-app="myApp" ng-controller="personCtrl">

名: <input type="text" ng-model="firstName"><br>
姓: <input type="text" ng-model="lastName"><br>
<br>
姓名: {{fullName()}}

</div>

<script>
var app = angular.module('myApp', []);
app.controller('personCtrl', function($scope) {
$scope.firstName = "John";
$scope.lastName = "Doe";
$scope.fullName = function() {
return $scope.firstName + " " + $scope.lastName;
}
});
</script>
  • 此处controller实现了 ng-init="firstName='John';lastName='Doe'" 的功能.
  • 可以将model中的变量全看做 $scope 的子成员,此时 $scope 即模型本身.
    • 注意controller代码中才使用 $scope, html代码中省略不写.
  • 模型中也可以定义函数,定义好的函数常用在表达式中或者 ng-click 等指令后.

分离html文件与js文件

html文件中使用 src 指定引用的js文件路径

1
<script src="namesController.js"></script>

应用工具

模型验证及状态

对于form中的元素,angularjs提供了检查状态和验证的功能,
(需要对form内部元素定义name属性和ng-model,实测没有ng-model的定义,验证不会生效)
还提供了配套的css定义等等,
就是为了验证数据后再以各种方式(显示文字,改变底色等等)反馈给使用者

angularjs提供的状态:
$error 表示是否有错误
$valid 表示是否合法
$dirty 值是否改变
$touched 是否被触摸(获取焦点?)
angularjs提供的错误
$error.email 是否违反email格式
$error.required 是否违反required
$error.number 是否违反number格式
等等
AngularJS还可以为input等标签预定义固定名字的设置,
无需 style="" 等方式定义,
进一步将验证的结果可视化

  1. 举例

    • 此处使用了 name 来定义变量的名字,是form中必须使用的.
    • $error.email 需要和 type="email" 配合
    • $error.required 需要和 required 配合
    • CSS ng-invalid 不需要再使用style属性声明
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <style>
    input.ng-invalid {
    background-color: lightblue;
    }
    </style>

    <form ng-app="" name="myForm">
    <p>邮箱:<br>
    <input type="email" name="email" ng-model="email" required>
    <span style="color:red" ng-show="myForm.email.$dirty && myForm.email.$invalid">
    <span ng-show="myForm.email.$error.required">邮箱是必须的。</span>
    <span ng-show="myForm.email.$error.email">非法的邮箱。</span>
    </span>
    </p>
    </form>
  2. 相关css属性

    • ng-empty
    • ng-not-empty
    • ng-touched
    • ng-untouched
    • ng-valid
    • ng-invalid
    • ng-dirty
    • ng-pending
    • ng-pristine

单页应用的CSS

  1. 表格中的使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <style>
    table, th , td {
    border: 1px solid grey;
    border-collapse: collapse;
    padding: 5px;
    }
    table tr:nth-child(odd) {
    background-color: #f1f1f1;
    }
    table tr:nth-child(even) {
    background-color: #ffffff;
    }
    </style>
  2. 数据验证中的使用

    参见模型验证及状态

动画

引入相应的库

1
<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular-animate.min.js"></script>

使用定义好的模型

1
<body ng-app="ngAnimate">

1
2
3
4
5
6
7
<body ng-app="myApp">
...

<script>
var app = angular.module('myApp', ['ngAnimate']);
</script>
</body>

然后 ng-hide 等就有了动画效果

  1. 也可以使用CSS实现动画

    例1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <style>
    div {
    transition: all linear 0.5s;
    background-color: lightblue;
    height: 100px;
    }
    .ng-hide {
    height: 0;
    }
    </style>

    例2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <style>
    @keyframes myChange {
    from {
    height: 100px;
    } to {
    height: 0;
    }
    }
    div {
    height: 100px;
    background-color: lightblue;
    }
    div.ng-hide {
    animation: 0.5s myChange;
    }
    </style>

路由

通过路由,AngularJS 可以实现多视图的单页 Web 应用(single page web application,SPA)

  1. 定义路由

    使用 #! + 路径 定义

    1
    2
    3
    4
    5
    6
    7
    <h2>AngularJS 路由应用</h2>
    <ul>
    <li><a href="#!/">首页</a></li>
    <li><a href="#!/computers">电脑</a></li>
    <li><a href="#!/printers">打印机</a></li>
    <li><a href="#!/blabla">其他</a></li>
    </ul>
  2. 定义view层资源

    使用了module ngRoute
    并在config中注入了 $routeProvider

    1
    2
    3
    4
    5
    6
    7
    8
    angular.module('routingDemoApp',['ngRoute'])
    .config(['$routeProvider', function($routeProvider){
    $routeProvider
    .when('/',{template:'这是首页页面'})
    .when('/computers',{template:'这是电脑分类页面'})
    .when('/printers',{template:'这是打印机页面'})
    .otherwise({redirectTo:'/'});
    }]);