AngularJS 学习笔记-第一章:速成

来源:互联网 发布:集金号软件下载 编辑:程序博客网 时间:2024/06/05 08:55

本文章是针对于刚开始学习angularJS的菜鸟们,根据(精通angularJS一书)做的精简版读书笔记, 旨在通过笔记让更多的前端开发,在一周之内可以入门AngularJS。

第一章 速成

1.快速使用
a.导入angularJS 库文件 (线上库或者离线库都可以,如果本地测试建议使用离线库,因为速度不是快一点点哦)
b.在html或者body DOM标签上添加 ng-app,表示这是一个angularJS的应用
c.初始化一个模型,并使用。ng-init初始化模型,并通过表达式 {{name}}传递值
<!DOCTYPE html><html><head>    <title></title>    <!-- 线上版本:https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.js    脱机版本,请从https://angularjs.org/ 下载angular.js并且放在html用目录下 -->    <script type="text/javascript" src='angular.js'></script></head><body ng-app ng-init="name='World'"><!-- input 的改变会直接反应在 下面的<p>-->    <input type="text" name="" ng-model="name">    <p>Hello, {{name}}</p></body></html>

hello world的例子没有明显的分层策略:数据初始化、逻辑和视图都混在了同一个文件中。通常情况我们希望把逻辑控制放倒一个controller里(ng-controller)来取而代之ng-init

<!DOCTYPE html><html><head>    <title></title>    <script type="text/javascript" src='angular.js'></script>    <script type="text/javascript">    // 1.3.0-beta.15 以后的版本不能直接定义controller,必须先定义model,再注入controller    var myModel = angular.module('myapp1', []).controller('myController', function($scope) {        $scope.name = 'eric';//$scope对象是末班的域模型    });    </script></head><!-- 必须要声明ng-app,不能使用匿名。myApp1对应于module名字--><body ng-app='myapp1'>    <div ng-controller="myController">        <input type="text" name="" ng-model="name">        <p>Hello, {{name}}</p>    </div></body></html>

2.作用域层级
  每个$scope都是Scope类实例,$scope类拥有很多方法,用于控制作用域的生命周期、提供事件传播功能,一级支持模板的渲染等。
  function($scope){} 只有参数,它是从何而来呢?
答案是ng-controller指令会去调用scope对象的$new()方法创建新的作用域$scope。看上去需要至少一个作用域实例才能创建新的作用域。确实如此,AngularJS拥有$rootScope,它是其他所有作用域的父作用域,将在新应用启动时自动创建
  ng-controller指令是作用域创建指令,DOM树中遇到作用域创建指令时,AngularJS都会闯将Scope类的新实例$scope,新创建的$scope会拥有$parent属性,并指向它的父作用域。
  某些指令会创建子作用域,如ng-repeat,对应每个country都有个新变量要暴露给$scope而且不能覆盖之前变量的值。AngularJS为了解决此问题,给集合中每个元素创建新的作用域。这些作用域会组成类似DOM树 层级结构,用Chrome的插件Batarang可以查看
  这里写图片描述

<!DOCTYPE html><html><head>    <title></title>    <script type="text/javascript" src="angular.js"></script>    <script type="text/javascript">    angular.module('myApp', []).controller('myController', function($scope) {        $scope.countries = [{            name: '中国',            population: '13亿'        }, {            name: '日本',            population: '1亿'        }];    });    </script></head><body ng-app='myApp'>    <div ng-controller='myController'>        <ul>            <li ng-repeat='country in countries'>                {{country.name}} has {{country.population}}            </li>        </ul>    </div></body></html>

  作用域中定义的属性对所有子作用域是可见的,只要子作用域没有定义同名属性。AngularJS中的作用域继承和Javascript的原型继承遵循同样的规则(沿继承树向上查找属性,直到倒找为止)。
  在进行read access的时候作用域层级的继承关系直观易懂。然而,进行write access是的情况就有些复杂了。访问父作用域的属性,就必须使用parent.name(使parent属性,因为塔在AngularJS表达式和模板创建的DOM结构间建立了强关联)
  推荐解决方案是将变量绑定为某个对象的属性,而不是直接绑定作用域的属性。如:

<!--错误的方式,子作用域的name和父作用域冲突覆盖之--><body ng-app='myapp1' ng-init="name='world'">    <h1>{{name}}</h1>    <div ng-controller="myController">        <input type="text" name="" ng-model="name">        <p>Hello, {{name}}</p>    </div></body><!--正确的方式--><body ng-app='myapp1' ng-init="thing={name:'world'}">    <h1>{{thing.name}}</h1>    <div ng-controller="myController">        <input type="text" name="" ng-model="thing.name">        <p>Hello, {{thing.name}}</p>    </div></body>

作用域通常在不需要的时候会被销毁(垃圾回收),也可以通过调用Scope类上的new()destroy()方法,手动创建和销毁作用域。

3.事件系统
事件可以从任何作用域开始分发(dispatch)。然后向上分发(emit广(broadcast).
这里写图片描述
AngularJS的核心服务与指令通过这趟事件列车来发送信号,通知应用状态的重要变化。例如,可以监听$locationChangeSuccess事件(由4rootDvope广播),当浏览器url变化时我们可以收到如下通知。

$scope.$on('$locationChangeSuccess', function(event, newUrl, oldUrl){//做出相应变化});//$on方法,用于注册作用域事件的处理器。与DOM事件一样event对象有preventDefault()和stopPropagation()方法。

AngularJS中,仅有三个事件可以被向上分发(emitted)

  1. $includeContentRequested
  2. $includeContentLoaded
  3. $viewContentLoaded
    七个事件可以被向下广播(broadcasted)
  4. $locationChangeStart
  5. $locationChangeSuccess
  6. $routeUpdate
  7. $routeChangeStart
  8. $routChangeSuccess
  9. $routeChangeError
  10. $destroy

4.模块与依赖注入
全局定义的控制器构造函数,只在简单代码示例和快速制作原型时才有用,永远不要在复杂的真是应用中使用全局定义的控制器。
让我们看看如何将丑陋的,全局定义的控制器模块化:

    //模块化之前,mycontroller是全局函数    var mycontroller = function($scope) {        $scope.name = 'eric';    }    //模块化之后,mycontroller只应用于ng-app=‘myapp1’的模块    var myModel = angular.module('myapp1', []).controller('myController', function($scope) {        $scope.name = 'eric';    });

依赖注入第一步,是将对象注册在module上,我们不直接注册对象的实例,而是将对象创建的方案抛给依赖注入系统,而后AngularJS解释这些方案以初始化对象,并在之后连接它们,最后成为可运行的应用。

AngularJS的provideinjector服务会解释这些方案,生成玩呗二可用的对象实例(已经解决好所有的依赖关系)

$injector服务创建的对象称之为服务(service)。在整个应用的生命中,每种方案AngularJS仅解释一次,也就是说,每个对象仅有一个实例。
原型继承

    var NotificationService = function (){        this.MAX_LEN = 10;        this.notificationsArchive = new NotificationsArchive();        this.notifications = [];    };    NotificationService.prototype.push = function(notification){        var newLen, notificationToArchive;        newLen = this.notification.unshift(notification);//unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。        if(newLen > this.MAX_LEN){            notificationToArchive = this.notifications.pop();            this.notificationsArchive.archive(notificationToArchive);        }    };    NotificationService.prototype.getCurrent = function(){        return this.notification;    };

Value注册
注册已经初始化好的对象,缺点是被注册的值必须是已经实例化好,并且不依赖于其他对象的

  //angularJS值(value)注入  var myapp1 = angualr.module('myapp1',[]);  myapp1.value('notificationsArchive', new NotificationsArchive());

Service注册
NotificationService依赖于notificationsArchive,所以他不能注册为值对象,

  //angularJS(serivce)服务注入,通过依赖注入,在NotificationService构造函数中可以消除new关键字,意味着此服务已经不依赖于其他对象的初始化,可以接受哦任何归档服务,这让应用变得非常灵活。  myapp1.service('notificationService',NotificationService);  //NotificationService构造函数  var NotificationService = function(notificationsArchive){    this.notificationsArchive = notificationsArchive;  }

Factory注册
另一条注册对象创建方案的途径是使用factory方法,任何能够创建对象的函数都可以被注册,因此它想必service而言更加灵活。factory是让对象加入依赖注入系统最常用的方法,它十分灵活,又能实现复杂的对象创建逻辑。

    myapp1.factory('NotificationService', function(notificationsArchive) {        this.MAX_LEN = 10;        this.notifications = [];        var ret = {            push: function(notification) {                var newLen, notificationToArchive;                newLen = this.notification.unshift(notification); //unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。                if (newLen > this.MAX_LEN) {                    notificationToArchive = this.notifications.pop();                    notificationsArchive.archive(notificationToArchive);                }            },            getCurrent: function() {                return this.notification;            }        }    });

constant注册

//理想状态下应该这样子获取配置,而不是写死在函数中myapp1.factory('NotificationService', function(notificationsArchive, MAX_LEN) {...});myapp1.constant('MAX_LEN', 10);

Provider
以上所有注册方法,都是最通用方法provider的特殊类型,下面是provider注册notificationsService的例子

//provider是一个函数,它返回包含$get属性的对象,改属性是一个工厂函数,它被调用时会返回service的实例,在$get方法被调用前,还能设置配置信息。实际上,我们能够设置maxLen    myapp1.provider('notificationsService', function() {        var config = {            maxLen: 10        };        var notifications = [];        return {            setMaxLen: function(max) {                config.maxLen = max || config.maxLen;            },            $get: function(notificationsArchive) {                return {                    {                        push: function(notification) {                            var newLen, notificationToArchive;                            newLen = this.notifications.unshift(notification); //unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。                            if (newLen > config.MAX_LEN) {                                notificationToArchive = this.notifications.pop();                                notificationsArchive.archive(notificationToArchive);                            }                        },                        getCurrent: function() {                            return this.notification;                        }                    }                }            }        }    });

模块的生命周期
如前所属,angularJS支持多装对象创建方案,provider是其中的通用方法,它在创建对象实例前可以对其进行配置。为了支持provider,angularJS将模块生命周期分为两个阶段,
1. 配置阶段
2. 运行阶段

//这里config对notificationServiceProvider有依赖,表明他是即将执行的对象创建方案,配置阶段允许我们对他进行最后的调整myapp1.config(function(notificationSerivceProvider){    notificationSerivceProvider.setMaxLen(5);});
//为了说明运行阶段的作用,我们假设要显示应用的已运行时间给用户。为了实现目标,我们将应用的已运行事假定义为$rootScope实例的属性,代码如下:myapp1.run(function($rootScope){    $rootScope.appstart = new Date();})

模块的生命周期

- 对象种类 可以在配置阶段注入 可以在运行阶段注入 Constant 常量值 Yes Yes Variable 变量值 - Yes Service 构造函数创建的新对象 - Yes Factory 工厂函数返回的新对象 - Yes Provider $get工厂函数创建的新对象 Yes -

模块依赖注入

//通知服务和归档服务,可以迁移到它们自己的模块中去(分别命名为notifications和archive)angular.module('application',['notifications','archive'])

跨模块的可见性
1. 定义在子模块的服务可以注入父模块

angular.module('app', ['engines'])    .factory('car', function($log, dieselEngine) {        return {            start: function() {                $log.info('starting' + dieselEngine.type);            }        }    });angular.module('engines', [])    .factory('dieselEngine', function() {        return { type: 'diesel' };    });
  1. 兄弟模块的服务也互相可见
angular.module('app', ['engines', 'cars']);angular.module('cars', [])    .factory('car', function($log, dieselEngine) {        return {            start: function() {                $log.info('starting' + dieselEngine.type);            }        }    });angular.module('engines', [])    .factory('dieselEngine', function() {        return { type: 'diesel' };    });
  1. 应用中的服务是不能被重名的,父模块的服务会被子模块中的同名模块覆盖。

5. 总结AngularJS 于JQuery
AngularJS内嵌jQuery的一个简化版本jqLite(是一个微小子集,只专注于操纵DOM的例程routine),内嵌jqLite后,AngularJS不再依赖其他外部库。
jQuery与AngularJS虽然可以合作,但是AngularJS围绕模型(由模型的变化来驱动模板(声明式)来更新UI),jQuery围绕DOM,它们是彻底不同的开发范型。

0 0
原创粉丝点击