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
  • 相关阅读:
    Fidder4 顶部提示 “The system proxy was changed,click to reenable fiddler capture”。
    redis 哨兵 sentinel master slave 连接建立过程
    虚拟点赞浏览功能的大数据量测试
    python基础练习题(题目 字母识词)
    python基础练习题(题目 回文数)
    python基础练习题(题目 递归求等差数列)
    python基础练习题(题目 递归输出)
    python基础练习题(题目 递归求阶乘)
    python基础练习题(题目 阶乘求和)
    python基础练习题(题目 斐波那契数列II)
  • 原文地址:https://www.cnblogs.com/wwjuan/p/5015242.html
Copyright © 2011-2022 走看看