浓缩解读前端系列书籍我爱编程

《用AngularJS开发下一代Web应用》读书笔记②:Angu

2016-11-24  本文已影响133人  梁同学de自言自语

调用Angular

<script 
    src="https://cdn.css.net/files/angular.all/1.2.18/angular-all.min.js">
</script>
<!-- 如果是构建纯Angular应用,可以写在`<html>`元素中 -->
<html ng-app>
    ···
</html>

或者

<html>
    <!-- 如果应用已经使用了类似JSP、Rails的其他技术,也可以写在要管理的DOM元素中 -->
    <div  ng-app>
        ···
    </div>
</html>

Model View Controller

<!doctype html>
<!-- 通过ng-app设置Angular管理的范围  -->
<html ng-app='myApp'>
    <head>
        <!-- 引入Angular的文件 -->
        <script src="https://cdn.css.net/files/angular.all/1.2.18/angular-all.min.js"></script>
    </head>
    <!-- 通过ng-controller声明控制器-->
    <body ng-controller='TextController'>
        <!-- 通过双花括号定义双向绑定的数据 -->
        <p>{{hello}} {{TextObj.message}}!</p>
        <script type="text/javascript">
            //通过angular.module()方法声明模块,第一个参数是模块名,第二个参数是需要依赖的模块(这里是空数组)
            var myAppModule = angular.module('myApp',[]);
            //通过module.controller()方法声明控制器,参数是控制器方法的具体实现
            myAppModule.controller('TextController',function($scope){
                //变量
                var hello = 'hello';
                //对象
                var TextObj = {
                    message : "World"   
                };  
                //赋值给$scope
                $scope.TextObj = TextObj;
                $scope.hello = hello;
            });
        </script>
    </body>
</html>

模板和数据绑定

<div ng-repeat='item in items'>
    <span>{{item.title}}</span>
</div>
显示文本
表单输入
<from ng-controller='SomeController'>
    <!-- 通过ng-model将控件值绑定到youCheckedIt变量中 -->
    <input type="checkbox" ng-model='youCheckedIt' />
</from>
<from ng-controller='StartUpController'>
    Starting: <input type="text" ng-model='funding.startingEstimate' />
    Remomendation:{{funding.needed}}
</from>
<script type="text/javascript">
    var myAppModule = angular.module('myApp',[]);
    myAppModule.controller('StartUpController',function($scope){
        $scope.funding = {startingEstimate : 0};
        $scope.computeNeeded = function(){
            $scope.funding.needed = $scope.funding.startingEstimate * 10;
        };
    });
</script>
myAppModule.controller('StartUpController',function($scope){
    $scope.funding = {startingEstimate : 0};
    $scope.computeNeeded = function(){
        $scope.funding.needed = $scope.funding.startingEstimate * 10;
    };
    //添加$watch
    $scope.watch('funding.startingEstimate',computeNeeded);
});
<from ng-controller='SomeController' ng-submit='requestFnding()'>
  ···
</from>
浅谈非入侵式JavaScript
列表、表格以及其他迭代类型
<!DOCTYPE html>
<!-- 1.通过ng-app设置Angular管理的范围 -->
<html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <!-- 2.引入Angular的文件 -->
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <ul ng-controller='StudentListController'>
            <li ng-repeat='student in students'>
                <a href="javascript:void(0);">{{$index+1}}.{{student.name}}</a>
            </li>
        </ul>
        <button ng-click='addStudent()'>Add</button>
        <script type="text/javascript">
            //伪数据
            var students = [
                {name : 'Mary Contrary',id:1},
                {name : 'Jack Spart',id:2},
                {name : 'Jill Hill',id:3},
                {name : 'William Liang',id:4},
                {name : 'Yoki Chen',id:5}
            ];
            var myApp = angular.module('myApp',[]);
            myApp.controller('StudentListController',function($scope){
                $scope.students = students;
                $scope.addStudent = function(){
                    $scope.students.splice(1,0,{name:'test',id:6});
                }
            });
        </script>
    </body>
</html>
显示和隐藏
<!DOCTYPE html>
<!-- 1.通过ng-app设置Angular管理的范围 -->
<html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <!-- 2.引入Angular的文件 -->
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <div ng-controller='SwichMenuController'>
            <button ng-click='toggleMenu()'>Add</button>    
            <ul ng-show='menuState.show'>
            </ul>   
        </div>
        <script type="text/javascript">
            var myApp = angular.module('myApp',[]);
            myApp.controller('SwichMenuController',function($scope){
                $scope.menuState.show = false;
                $scope.toggleMenu = function(){
                    $scope.menuState.show = !$scope.menuState.show;
                }
            });
        </script>
    </body>
</html>
CSS类和样式
<!DOCTYPE html>
<html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .menu-disabled-true{ color:gray }
        </style>
    </head>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <div ng-controller='StudentListController'>
            <ul>
                <li class="menu-disabled-{{isDisabled}}" ng-click='stun()'></li>
            </ul>   
        </div>
        <script type="text/javascript">
            var myApp = angular.module('myApp',[]);
            myApp.controller('SwichMenuController',function($scope){
                $scope.isDisabled = false;
                $scope.stun = function(){
                    $scope.isDisabled = true;
                }
            });
        </script>
    </body>
</html>
<!DOCTYPE html>
<html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .error{background-color: red;}
            .warrning{background-color: yellow;}
        </style>
    </head>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <div ng-controller='HeaderController'>
            <div ng-class='{error:isError,warning:isWarning}'>
                {{messageText}}
            </div>
        </div>
        <button ng-click='showError()'>Simulate Error</button>
        <button ng-click='showWarning()'>Simulate Warning</button>
        <script type="text/javascript">
            var myApp = angular.module('myApp',[]);
            myApp.controller('HeaderController',function($scope){
                $scope.isError = false;
                $scope.isWarning = false;
                
                $scope.showError = function(){
                    $scope.messageText = 'This is an Error';
                    $scope.isError = true;
                    $scope.isWarning = false;
                };
                
                $scope.showWarning = function(){
                    $scope.messageText = 'This is an Warning';
                    $scope.isWarning = true;
                    $scope.isError = false;
                };
            });
        </script>
    </body>
</html>
反思src和href属性
<img ng-src='/images/cats/{{favoriteCat}}'>
<a ng-href='/shop/category={{numberOfBalloons}}'>some text</a>
表达式
区分UI和控制器和职责
<!-- ChildController的$scope对象可以访问ParentController的$scope对象上所有的属性 -->
<div ng-controller='ParentController'>
    <div ng-controller='ChildController'></div>
</div>
利用$scope暴露模型数据
<!-- ① 可以直接在模板表达式中定义变量 -->
<button ng-click='count=3'>Set Count to Three</button>
<!-- ② 也可以通过构造器函数定义变量 -->
<div ng-controller='CountController'>
   <button ng-click='setCount()'>Set Count to Three</button>
</div>
<script type="text/javascript">
function CountController($scope){
   $scope.setCount = function(){
        $scope.count = 3;
   };
}
</script>
使用$watch监控数据模型的变化
//监听someProperty属性值的变化
var dereg = $scope.$watch('someModel.someProperty',callbackOnChange());
dereg();    //销毁
watch()中的性能注意事项

$scope.$watch('things.a+things.b',callMe(...));

2. 将要监控的属性放到一个数组或者对象中,并将`deepWatch`参数设置成true;

$scope.$watch('things',callMe(...),true);



### 使用Module(模块)组织依赖关系
- 在开发中经常会遇到的难题是 __如何把代码组织在合理的功能范围内?__ 
- MVC的处理方式,是将控制器看做一个解耦的方法,把正确的数据模型暴露给视图模板。但其他用来支撑我们应用的代码该怎么办?要把它们写在控制器函数里面吗?这么做会使控制器变成一个垃圾场,使得控制器的代码变得难以理解,无法维护。
- `模块机制`解决了上诉问题,它把那些负责提供特殊服务的代码称为`依赖服务`,它专门来组织应用中各个功能区块的依赖关系,甚至可以自动进行依赖注入。
- 案例:当控制器需要从服务器获取商品列表时,通常情况我们会把相关的处理通通写到一个方法中

function ItemsViewController($scope){
var items = [];
//1.向服务器发起请求
//2.解析响应并放到Items对象
//3.将Items数组设置到$scope上,以便视图能够显示
$scope.items = items;
}

- 这种做法虽然可行,但却存在很多问题:
    * 功能代码无法重用:同样的代码片段,如果其他控制器也需要从服务端获取商品列表时,却只能重写一遍,这会给代码维护工作造成很大的负担;
    * 混淆控制器与与获取数据功能之间的代码边界:获取数据功能如果需要加上一些,例如服务器认证、解析数据等因素时,代码的复杂性将变得不可控制;
    * 难以进行单元测试:进行测试的工作变得复杂,甚至可能需要真正启动一个服务器来返回模拟数据进行测试,使得测试工作难以把控;
  通过模块化和Angular内置的依赖注入功能,可以这样写:

//创建模块
var myApp = angular.module('shoppingModule',[]);
//设置服务工厂
shoppingModule.factory('Items',function(){
var items = {};
items.query = function(){
//这里返回虚拟数据,真实的场景是从服务器拉取数据
return [
{name : 'Mary Contrary',id:1},
{name : 'Jack Spart',id:2},
{name : 'Jill Hill',id:3},
{name : 'William Liang',id:4},
{name : 'Yoki Chen',id:5}
];
};
return items;
});
//调用
function ShoppingController($scope,Items){
$scope.items = items.query();
}

  我们把`Items`对象定义成一个服务,把`$scope`对象和`Items`服务作为参数传递进去。
  > 提示:传递Angular在创建控制器时,是通过参数名匹配来注入所需要的服务的,比如`ShoppingController($scope,Items)`中查找`Items`服务。由于是以字符串的形式查找依赖关系的,所以控制器的参数是没有顺序的。

- 服务在Angular当中都是单例的对象,它们用来执行不要的任务,支撑应用的功能。开发者通过创建自定义的服务,共享在控制器之间,实现代码的复用。
- Angular内置了很多服务,例如`location`服务,用来和浏览器的地址栏做交互;还有`router`服务,用来根据URL地址的变化切换视图;以及`http`服务,用来和服务器进行交互等等;
- 根据Angular的API,有三种创建服务的函数:
  * __`provider(name,Object OR constructor())`__ :`name`是服务的名字,后面接一个对象或者构造函数。如果是Object的话,对象当中必须返回一个名为`$get()`的函数,否则Angular会认为传递的是一个构造函数,通过调用改构造函数返回服务的实例;
  * __`factory(name,$getFunction())`__ :和`provider()`函数相似,服务名后面接一个构造函数,当调用这个函数时,会返回服务的实例;
  * __`service(name,constructor())`__ :和`constructor`参数类似,Angular调用它来创建服务实例;
> 需要注意的是:Angular内置服务通常以符号开头,为了避免命名冲突,定义服务名时应当避免以$符号打头。

- 服务自身可以相互依赖,也可以通过`Module`接口定义模块之间的依赖关系。比如:A模块要引用SnazzyUIWidgets和SuperDataSync模块

var appMod = angular.module('app',['SnazzyUIWidgets','SuperDataSync']);




### 使用过滤器格式数据
- 合理化地在应用界面中显示数字、日期以及金额对于用户体验来说是很重要的,但这些字符串的格式化处理对逻辑来说是没有意义的。
- Angular通过过滤器来格式化数据,其语法是:`{{expression | filterName : parameter1 : ...parameterN }}`
- `expression`可以是任意的Angular表达式,`filter`是需要使用的过滤器名称,过滤器通过管道符号`|`来绑定,过滤器的参数之间使用冒号`:`分隔。
- 案例:Angular内置了众多过滤器帮助我们格式化数据,同时也可以创建自定义的过滤器

//大小写转换
{{ "lower cap string" | uppercase }} //结果:LOWER CAP STRING
{{ "TANK is GOOD" | lowercase }} //结果:tank is good
//JSON格式化
{{ {foo: "bar", baz: 23} | json }} //结果:{ "foo": "bar", "baz": 23 }
//时间或日期格式化
{{ 1304375948024 | date:"yyyy-MM-dd hh:mm:ss" }} //结果:2011-05-03 06:39:08
//数字格式化
{{ 1.234567 | number:1 }} //结果:1.2
//金额格式化
{{ 250 | currency:"人民币: ¥ " }} //结果:“人民币: ¥ 250.00 ”
//排序格式化
{
{ [{"age": 20,"id": 10,"name": "iphone"},
{"age": 12,"id": 11,"name": "sunm xing"},
{"age": 44,"id": 12,"name": "test abc"}
] | orderBy:'id':true }} //根id降序排
//查找格式化
{
{ [{"age": 20,"id": 10,"name": "iphone"},
{"age": 12,"id": 11,"name": "sunm xing"},
{"age": 44,"id": 12,"name": "test abc"}
] | filter:'s'}} //查找含有有s的行
//字符串截取的格式化
{{ "i love tank" | limitTo:6 }} //结果:i love
{{ "i love tank" | limitTo:-4 }} //结果:tank



### 使用路由和$location切换视图
- 虽然从技术角度来说,Ajax应用是单页面应用,但很多时候处于各种原因,我们需要切换跳转页面,而Angular的`$router`服务负责应对这样的场景。
- 路由服务机制是这样定义的:当浏览器指向特定的URL时,Angular会加载显示一个模板,并实例化一个控制器为此模板提供内容。
- 开发者可以通过`$routerProvider`服务的函数来创建路由,把需要创建的路由当做一个配置项传递给这些函数。

//创建模块
var someModule = angular.module('someModule',[...module dependencies...]);
someModule.config(function($routerProvider){
//通过$routerProvider定义url对应的跳转动作所需要的模板和控制器
$routerProvider.
when('url',{controller:aController,templateUrl:'/path/to/tempate'}).
othenwise('badUrl',{controller:notFoundController,templateUrl:'/path/to/tempate'});
});



### 与服务器交互
- Angular提供的`$http`服务使得与服务器交互更加容易。它支持HTTP、JSONP和CORS方式。它还包含了安全性支持,避免JSON格式的脆弱性和XSRF。

function ShoppingController($scope,$http){
$http.get('/products').success(function(data,status,headers.config){
$scope.items = data;
});
};



### 使用指令修改DOM
- Angular指令扩展了HTML的语法,通过自定义的元素或者属性,把行为和DOM转换关联到一起。通过Angular可以创建可复用的UI组件。
- Angular指令创建语法:(directiveFn是一个工厂函数,用来定义指令的特性)

var app = angular.module('myapp',[]);
app.directive(name,fn);

- 案例:定义ts-hello指令,向DOM中输出“Hello,Angular Directive!”

<!DOCTYPE html>
<html ng-app="DirectiveTestApp">
<head>
<meta charset="UTF-8">
<title>AngularJS Directive</title>
<style></style>
</head>
<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
<body>
<div ng-controller="SomeController">
<ts-hello></ts-hello>
<div ts-hello></div>
<div class="ts-hello"></div>
<div data-ts-hello></div>
</div>
</body>
<script type="text/javascript">
var app = angular.module('DirectiveTestApp', []);
app.directive("tsHello",function(){
return {
restrict : 'EAC',
template : '<h5>Hello,Angular Directive!</h5>'
}
});
</script>
</html>



### 校验用户输入
- 在表单校验上,Angular允许开发者为表单的元素定义一个个发的状态,只有当所有元素都是合法状态时,才允许提交表单。
- 案例:一个用户注册页面,要求必须输入用户名和邮箱,使用H5的required属性

<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Sign Up</h1>
<form name="addUserForm" ng-controller="AddUserController">
<div ng-show="message">{{message}}</div>
First name : <input name="firstName" required/>
Last name : <input name="lastName" required/>
Email : <input name="email" required type="email"/>
Age : <input name="age" required type="number"/>
<button ng-click="addUser()" ng-disabled="!addUserForm.$valid">Submit</button>
</form>
<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp',[]);
myApp.controller('AddUserController',function($scope){
$scope.message = '';
$scope.AddUser = function(){
alert("add user success!");
}
});
</script>
</body>
</html>

上一篇 下一篇

猜你喜欢

热点阅读