zoukankan      html  css  js  c++  java
  • AngularJS之禅

    AngularJS是客户端MVC框架,它运行在web浏览器中,有助于我们写单页面、AJAX风格的web应用,是一个通用的框架。
     
    AngularJS速成
    实例:Hello World
    首先引用AngularJS库angular.js。使用自定义的ng-app的HTML属性来运行。仔细观察<body>标签,有另一个非标准的HTML属性:ng-init,渲染模版前使用ng-init来初始化model。
    AngularJS模版系统重要特性:
      使用自定义HTML标签和属性为静态html文档添加动态行为
      使用双大括号{{}}输出模型值
    AngularJS中,框架理解和解释的所有特别的HTML标签和属性都可以称为指令。

    双向数据绑定
    不需要刷新模板,不需要使用框架API来更新模型,AngularJS可以智能检测模型变化且相应的更新DOM,任何视图的变化都会立刻反应到模型中,任何模型的变化也会反应到模版上。
     
    AngularJS中的MVC模式
    Scope
    scope对象是提供模型给视图(模板)。通过将属性赋值给scope的实例,可以生成新值来渲染模板。对于给定视图,scope能够用数据和特定的功能来扩充。可以通过在scope实例上定义功能提供具体的UI逻辑给模板。
    例如可以为name变量创建一个getter函数:
    可以在模版中使用函数:
    scope使我们能够精确控制domain模型的哪部分、哪些操作对视图层可用。
     
    Controller
    主要职责是初始化scope对象。具体包括:
      提供初始模型值
      通过UI交互(函数)来扩充scope
    controller是正常的js功能函数。没有扩展任何具体框架类,不调用任何特定的AngularJS的api来执行操作,也不操作html模板和dom。
     
    Model
    仅是js的对象,不继承任何框架基类,不以任何特别方式构建模型对象。为了提供模型给AngularJS,仅需要将模型赋值给scope。
     
    深入理解scope
    每个$scope是Scope类的实例,Scope类有方法控制scope生命周期,提供事件传播机制,支持模版渲染过程。
     
    scopes层级
    ng-controller指令使用scope.$new()方法创建新的scope。angularjs有个根作用域$rootScope(所有其他作用域的父亲),新建应用时就有rootScope。
    ng-controller指令是scope创建指令的例子。AngularJS碰到dom树中scope创建指令时就会创建scope类的一个新的实例。(ng-repeat可以生成多个scope实例)新创建的scope使用parent属性指向其父亲。
     
    scope层级和继承
    一个scope上定义的属性可以对所有子scope可见,只是子scope 不能使用相同的名字重定义这个属性。
    scope的继承跟原型链继承一样。继承中读很容易理解,写有点复杂。
    如下代码:
    运行此代码,name变量在整个应用中可见,即使它只在最高层scope中定义。
    跟js原型继承一样,子类的值不会影响父类的值。如果要改变父域的值,有几种方式:
    1、使用$parent属性
    通过直接指向父scope解决问题,麻烦的是,使用ng-model指令表达式作用在整个DOM结构上,在其他<input>标签上插入另一个scope-creating指令,$parent将会指向另一个完全不同的scope. 所以应该避免使用$parent属性。 
    2、将属性绑定到一个对象上,并不直接指向一个scope属性。如下:
    这个方法不会在DOM树结构上假定任何属性。避免直接绑定到scope的属性上。绑定到对象属性上是更好的方法。如ng-model="thing.name"
     
    scope层级关系和事件系统
    层级上的scope可用来作为事件总线。AngularJS让我们通过scope的层级关系传播命名事件。事件可以从任意一个scope上发出,向上($emit)或者向下($broadcast)传播。
     
    AngularJS核心服务和指令使用这个事件总线标志应用状态的重要变化。例如,当location(URL)变化时可以监听$locationChangeSucess事件:
    每个scope实例上的$on方法可以用来注册scope-event处理函数。类似于DOM事件,可以在event对象上调用preventDefault()和stopPropagation()方法。stopPropagation()方法将会阻止事件冒泡到scopes层级上,仅可以通过($emit)来向上发送事件。
    在整个AngularJS框架中,只有三个emit的事件($includeContentRequested,$includeContentLoaded,$viewContentLoaded),和几个broadcast的事件($locationChangeStart,$loactionChangeSuccess,$routeUpdate,$routeChangeStart,$routeChangeSuccess,  $routeChangeError ,$destroy)。scope事件使用非常谨慎,在发出自定义事件之前需要评估其他选项(主要是双向数据绑定)。
     
    scope生命周期
    scope提供了独立的命名空间,避免变量名冲突。在层级上组织scopes有利于管理内存。当scopes中的一个scope不需要了,可以destroy。因此,这个scope上的model和functionality也会被垃圾回收。可以通过scope-creating指令创建新的scope,可以通过调用$new()和$destroy()方法手动创建和销毁scope.
     
    View
    声明式模板视图
    AngularJS提倡声明式方法构建UI,即模版集中于描述想要的效果而不是如何实现。举例如下:
    需要创建一个表单,用户输入一段message并发送。message的长短限制在100个字符,如果长度超出,Send button将会disable。用户需要知道还可以输入多少字符。如果剩下的字符小于10,显示字符数的style将会变化来提醒用户。如下所示:
    初步实现如下所示:
     
    加上显示的剩余字符数:
    其次,如果message不符合长度限制,需要使Send按钮失效。
    当仅有几个字符剩下时需要改变样式:
     
    声明式指令表达想要的结果,避免操作DOM元素。
     
    模块和依赖注入
    模块化
    如何将全局定义的controller简化为module。
    使用modules变为:
     
    module像是angularjs已组织的对象(controllers,services等)的容器。为了定义一个module,需要提供第一个参数name。第二个参数来表示依赖的其他模块。
    调用angular.module函数返回一个新创建的module实例,进入这个实例,可以定义controllers。controller函数有以下参数:
         Controller名称
         Controller构造函数
    通过ng-app属性告知AngularJS module的存在
    协作对象
    module不仅可以用来注册angularjs框架直接调用的对象如controllers、filters等,也可以是任何应用开发人员定义的对象。还可以描述这些对象之间的依赖关系。
     
    注入依赖
    scope对象可以注入到控制器实例中。AngularJS可以找出一个controller需要的新的scope实例,并能创建一个新的scope实例将scope实例注入到controller中。
    angularjs的注入依赖执行以下功能:
      理解需要用对象表示collaborator
      找到需要的collaborator
      将对象包装成全功能的应用
     
    注册服务
    AngularJS只能连接它知道的对象。第一步注入依赖注入的机制:注册一个module对象,不是直接注册对象实例,而是抛出对象创建方法给AngularJS的依赖注入系统。其次AngularJS解释这些方法将对象实例化后再连接它们。最后连接的对象集合组成了可运行的应用。
    AngularJS中,有一个特定的$provide服务可以注册不同的方法来创建对象。注册的方法然后由$injector翻译来提供可以使用的对象实例(有所有的依赖resolved和injected)
    $injector服务创建的对象指向了服务,在应用生命周期中,AngularJS将解释给定的方法仅一次,所以仅能创建单个对象实例。
    被$injector服务创建的对象即是服务。angularjs仅仅解释给定的方法一次,所以仅仅会创建对象的一个单例。services是单例对象。
    AngularJS仅仅是对象实例的集合,我们可以控制这些对象如何创建。
     
    Services
    不能注册NotificationsService服务为一个value对象,因为需要与存档服务表达依赖关系。依赖其他对象,为一个对象注册方法的最简单的方式是注册一个结构化函数。可使用以下service方法:
    NotificationsService结构化函数可以写成如下:
    通过使用AngularJS依赖注入,可以从NoificiationsService构造函数中消除新的关键字。这个服务与依赖的实例无关,可接受任何存档服务。应用更灵活!
    实际上service方法不常使用,但对于注册预先存在的构造函数还是很方便的,这样AngularJS可以管理由这些构造函数创建的对象。
     
    Factories
    是另一种创建对象的注册方法,比service更加灵活,因为可以注册任何抽象的对象创建函数,如下:
    AngularJS将使用提供的factory函数注册一个返回对象。可以是任意有效的JS对象,包括function对象。
    factory方法是将对象放入AngularJS依赖注入系统的最常用方法。
     
    Constants
    constants可以在模块级别上定义并作为其他协作对象注入。
    Constants对于创建services很有用,可以在多个不同应用中重用。有一个缺点是只要一个service依赖于一个constant,这个constant值必须提供。所以有时需要有默认的配置值并允许用户根据需要修改比较好。
     
    Providers
    所有注册方法只是Provider的特例。注册notificationsService服务为一个provider的例子如下:
    首先provider是一个函数,返回包含$get属性的对象。$get属性是一个factory函数,返回一个service实例。可以将providers视为对象,将factory函数嵌入到$get属性中。
    其次,从provider函数返回的对象有额外的方法和属性。所以在$get方法触发前可能设置配置选项,也可以设置maxLen属性。可能有更复杂的配置逻辑,因为服务还可以暴露配置方法。
     
    模块的生命周期
    为了支持providers,AngularJS将模块的生命周期分为两个阶段:
    配置阶段:收集并配置所有方法
    运行阶段:执行任何后期实例化逻辑
     
    配置阶段
    providers仅仅在配置阶段配置。providers可配置如下:
    依赖有Provider后缀的notificationsServiceProvider对象表示方法准备执行。配置阶段可以对对象创建方法做最后调整。
     
    执行阶段
    执行阶段可以注册任何需要在application bootstrap上执行的功能,可以将运行阶段视为其他程序中主要方法。AngularJS模块最大的区别是有多个配置和运行块,不止一个入口。
    如下:
    模板:
    不同阶段不同注册方法,总结下创建对象的不同方法以及这些方法对应的module的生命周期:
     
    模块依赖
    AngularJS不仅可以管理对象依赖,也可以管理模块间的依赖关系。可以很容易的将相关services组成一个module,创建service库。
    例如,可以将notifications和archiving services移动到他们自己的modules中,如下:
    这种方式每个service(或者相关services的集合)可以组合成一个可复用的实体(a module)。最高级别的模块可以声明所有模块的依赖关系。
     
    AngularJS模块可以相互依赖,每个模块有几个services,但是各自的services可以依赖其他的services。这会引发几个有趣的问题:
      一个AngularJS模块上定义的service依赖于另一个模块的services?
      子模块中定义的service可以依赖父模块的service或者其他子模块中定义的services?
      可以仅对特定module中可见的私有模块services吗?
      在不同模块中可以有同样名字的services吗?
     
    Services和模块间的可见性
    car服务定义在app模块中。app模块声明了对engines模块的依赖,dieselEngine服务定义在这个模块上。car可以被engine的一个实例注入。
    定义在相邻模块上的services相互之间都可见。可以将car服务移到单独的模块,然后改变模块依赖,依赖engines和cars模块的应用如下:
    在之前的例子中,engine仍然可以注入到car中。
    定义在应用中的modules中的service可以对其他所有模块可见。 
    因为AngularJS结合所有模块中的所有服务成一个大的应用层级的services,仅有一个给定名字的service。这点可以在依赖一个模块但又想覆盖模块中的某些services情况下使用。可以直接在cars模块中重定义dieselEngine service如下:
     
    当前AngularJS版本中,在一个模块上定义的所有services对所有其他模块都可见,无法限制一个模块或者模块子集上的服务的可见性。
     
    初写文章,译的不合适的地方,还望大牛们不吝赐教!!!
    英文原文:Mastering Web Application Development with AngularJS
  • 相关阅读:
    2020-2021-1 20209323 《linux内核原理与分析》第十二周作业
    2020-2021-1 20209323《Linux内核原理与分析》第九周作业
    2020-2021-1 20209323 《Linux内核原理与分析》 第八周作业
    2020-2021-1 20209323《Linux内核原理与分析》第七周作业
    2020-2021-1 20209323《Linux内核原理与分析》第六周作业
    2020-2021-1 20209323《Linux内核原理与分析》第五周作业
    2020-2021-1 20209323《Linux内核原理与分析》第四周作业
    2020-2021-1 20209323 《linux内核原理与分析》第三周作业
    2020-2021-1 20209323 《linux内核原理与分析》第二周作业
    软工实践个人总结
  • 原文地址:https://www.cnblogs.com/wwjuan/p/5015242.html
Copyright © 2011-2022 走看看