非常教程

AngularJS参考手册

组件与模板

结构型指令

本章将看看 Angular 如何用结构型指令操纵 DOM 树,以及你该如何写自己的结构型指令来完成同样的任务。

试试在线例子 / 下载范例。

什么是结构型指令?

结构型指令的职责是 HTML 布局。 它们塑造或重塑 DOM 的结构,比如添加、移除或维护这些元素。

像其它指令一样,你可以把结构型指令应用到一个宿主元素上。 然后它就可以对宿主元素及其子元素做点什么。

结构型指令非常容易识别。 在这个例子中,星号(*)被放在指令的属性名之前。

src/app/app.component.html (ngif)

content_copy<div *ngIf="hero" class="name">{{hero.name}}</div>

没有方括号,没有圆括号,只是把 *ngIf 设置为一个字符串。

在这个例子中,你将学到星号(*)这个简写方法,而这个字符串是一个微语法,而不是通常的模板表达式。 Angular 会解开这个语法糖,变成一个 <ng-template> 标记,包裹着宿主元素及其子元素。 每个结构型指令都可以用这个模板做点不同的事情。

三个常用的内置结构型指令 —— NgIf、NgFor和NgSwitch...。 你在模板语法一章中学过它,并且在 Angular 文档的例子中到处都在用它。下面是模板中的例子:

src/app/app.component.html (built-in)

content_copy<div *ngIf="hero" class="name">{{hero.name}}</div>

<ul>
  <li *ngFor="let hero of heroes">{{hero.name}}</li>
</ul>

<div [ngSwitch]="hero?.emotion">
  <app-happy-hero    *ngSwitchCase="'happy'"    [hero]="hero"></app-happy-hero>
  <app-sad-hero      *ngSwitchCase="'sad'"      [hero]="hero"></app-sad-hero>
  <app-confused-hero *ngSwitchCase="'app-confused'" [hero]="hero"></app-confused-hero>
  <app-unknown-hero  *ngSwitchDefault           [hero]="hero"></app-unknown-hero>
</div>

本章不会重复讲如何使用它们,而是解释它们的工作原理以及如何写自己的结构型指令。

指令的拼写形式

在本章中,你将看到指令同时具有两种拼写形式大驼峰 UpperCamelCase 和小驼峰 lowerCamelCase,比如你已经看过的 NgIf ngIf。 这里的原因在于,NgIf 引用的是指令的类名,而 ngIf 引用的是指令的属性名*。

指令的类名拼写成大驼峰形式NgIf),而它的属性名则拼写成小驼峰形式ngIf)。 本章会在谈论指令的属性和工作原理时引用指令的类名,在描述如何在 HTML 模板中把该指令应用到元素时,引用指令的属性名

还有另外两种 Angular 指令,在本开发指南的其它地方有讲解:(1) 组件 (2) 属性型指令。

组件可以在原生 HTML 元素中管理一小片区域的 HTML。从技术角度说,它就是一个带模板的指令。

属性型指令会改变某个元素、组件或其它指令的外观或行为。 比如,内置的NgStyle指令可以同时修改元素的多个样式。

你可以在一个宿主元素上应用多个属性型指令,但只能应用一个结构型指令。

NgIf 案例分析

NgIf 是一个很好的结构型指令案例:它接受一个布尔值,并据此让一整块 DOM 树出现或消失。

src/app/app.component.html (ngif-true)

content_copy<p *ngIf="true">
  Expression is true and ngIf is true.
  This paragraph is in the DOM.
</p>
<p *ngIf="false">
  Expression is false and ngIf is false.
  This paragraph is not in the DOM.
</p>

ngIf 指令并不是使用 CSS 来隐藏元素的。它会把这些元素从 DOM 中物理删除。 使用浏览器的开发者工具就可以确认这一点。

结构型指令

可以看到第一段文字出现在了 DOM 中,而第二段则没有,在第二段的位置上是一个关于“绑定”的注释(稍后有更多讲解)。

当条件为假时,NgIf 会从 DOM 中移除它的宿主元素,取消它监听过的那些 DOM 事件,从 Angular 变更检测中移除该组件,并销毁它。 这些组件和 DOM 节点可以被当做垃圾收集起来,并且释放它们占用的内存。

为什么移除而不是隐藏

指令也可以通过把它的 display 风格设置为 none 而隐藏不需要的段落。

src/app/app.component.html (display-none)

content_copy<p [style.display]="'block'">
  Expression sets display to "block".
  This paragraph is visible.
</p>
<p [style.display]="'none'">
  Expression sets display to "none".
  This paragraph is hidden but still in the DOM.
</p>

当不可见时,这个元素仍然留在 DOM 中。

结构型指令

对于简单的段落,隐藏和移除之间的差异影响不大,但对于资源占用较多的组件是不一样的。 当隐藏掉一个元素时,组件的行为还在继续 —— 它仍然附加在它所属的 DOM 元素上, 它也仍在监听事件。Angular 会继续检查哪些能影响数据绑定的变更。 组件原本要做的那些事情仍在继续。

虽然不可见,组件及其各级子组件仍然占用着资源,而这些资源如果分配给别人可能会更有用。 在性能和内存方面的负担相当可观,响应度会降低,而用户却可能无法从中受益。

当然,从积极的一面看,重新显示这个元素会非常快。 组件以前的状态被保留着,并随时可以显示。 组件不用重新初始化 —— 该操作可能会比较昂贵。 这时候隐藏和显示就成了正确的选择。

但是,除非有非常强烈的理由来保留它们,否则你会更倾向于移除用户看不见的那些 DOM 元素,并且使用 NgIf 这样的结构型指令来收回用不到的资源。

同样的考量也适用于每一个结构型指令,无论是内置的还是自定义的。 你应该提醒自己慎重考虑添加元素、移除元素以及创建和销毁组件的后果。

星号(*)前缀

你可能注意到了指令名的星号(*)前缀,并且困惑于为什么需要它以及它是做什么的。

这里的 *ngIf 会在 hero 存在时显示英雄的名字。

src/app/app.component.html (asterisk)

content_copy<div *ngIf="hero" class="name">{{hero.name}}</div>

星号是一个用来简化更复杂语法的“语法糖”。 从内部实现来说,Angular 把 *ngIf 属性 翻译成一个 <ng-template> 元素 并用它来包裹宿主元素,代码如下:

src/app/app.component.html (ngif-template)

content_copy<ng-template [ngIf]="hero">
  <div class="name">{{hero.name}}</div>
</ng-template>
  • *ngIf 指令被移到了 <ng-template> 元素上。在那里它变成了一个属性绑定 [ngIf]
  • <div> 上的其余部分,包括它的 class 属性在内,移到了内部的 <ng-template> 元素上。

第一种形态永远不会真的渲染出来。 只有最终产出的结果才会出现在 DOM 中。

结构型指令

Angular 会在真正渲染的时候填充 <ng-template> 的内容,并且把 <ng-template> 替换为一个供诊断用的注释。

NgForNgSwitch...指令也都遵循同样的模式。

*ngFor 内幕

Angular 会把 *ngFor 用同样的方式把星号()语法的 template属性转换成 <ng-template>元素*。

这里有一个 NgFor 的全特性应用,同时用了这三种写法:

src/app/app.component.html (inside-ngfor)

content_copy<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
  ({{i}}) {{hero.name}}
</div>

<ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
  <div [class.odd]="odd">({{i}}) {{hero.name}}</div>
</ng-template>

它明显比 ngIf 复杂得多,确实如此。 NgFor 指令比本章展示过的 NgIf 具有更多的必选特性和可选特性。 至少 NgFor 会需要一个循环变量(let hero)和一个列表(heroes)。

你可以通过把一个字符串赋值给 ngFor 来启用这些特性,这个字符串使用 Angular 的微语法。

ngFor 字符串之外的每一样东西都会留在宿主元素(<div>)上,也就是说它移到了 <ng-template> 内部。 在这个例子中,[ngClass]="odd" 留在了 <div> 上。

微语法

Angular 微语法能让你通过简短的、友好的字符串来配置一个指令。 微语法解析器把这个字符串翻译成 <ng-template> 上的属性:

  • let 关键字声明一个模板输入变量,你会在模板中引用它。本例子中,这个输入变量就是 heroiodd。 解析器会把 let herolet ilet odd 翻译成命名变量 let-herolet-ilet-odd
  • 微语法解析器接收 oftrackby,把它们首字母大写(of -> Of, trackBy -> TrackBy), 并且给它们加上指令的属性名(ngFor)前缀,最终生成的名字是 ngForOfngForTrackBy。 还有两个 NgFor输入属性,指令据此了解到列表是 heroes,而 track-by 函数是 trackById
  • NgFor 指令在列表上循环,每个循环中都会设置和重置它自己的上下文对象上的属性。 这些属性包括 indexodd 以及一个特殊的属性名 $implicit(隐式变量)。
  • let-ilet-odd 变量是通过 let i=indexlet odd=odd 来定义的。 Angular 把它们设置为上下文对象中的 indexodd 属性的当前值。
  • 这里并没有指定 let-hero 的上下文属性。它的来源是隐式的。 Angular 将 let-hero 设置为此上下文中 $implicit 属性的值, 它是由 NgFor 用当前迭代中的英雄初始化的。
  • API 参考手册中描述了 NgFor 指令的其它属性和上下文属性。
  • NgFor 是由 NgForOf 指令来实现的。请参阅NgForOf API reference来了解 NgForOf 指令的更多属性及其上下文属性。

这些微语法机制在你写自己的结构型指令时也同样有效,参考NgIf 的源码和NgFor 的源码 可以学到更多。

模板输入变量

模板输入变量是这样一种变量,你可以在单个实例的模板中引用它的值。 这个例子中有好几个模板输入变量:heroiodd。 它们都是用 let 作为前导关键字。

模板输入变量和模板引用变量是不同的,无论是在语义上还是语法上。

你使用 let 关键字(如 let hero)在模板中声明一个模板输入变量。 这个变量的范围被限制在所重复模板的单一实例上。 事实上,你可以在其它结构型指令中使用同样的变量名。

而声明模板引用变量使用的是给变量名加 # 前缀的方式(#var)。 一个引用变量引用的是它所附着到的元素、组件或指令。它可以在整个模板任意位置访问。

模板输入变量和引用变量具有各自独立的命名空间。let hero 中的 hero#hero 中的 hero 并不是同一个变量。

每个宿主元素上只能有一个结构型指令

有时你会希望只有当特定的条件为真时才重复渲染一个 HTML 块。 你可能试过把 *ngFor*ngIf 放在同一个宿主元素上,但 Angular 不允许。这是因为你在一个元素上只能放一个结构型指令。

原因很简单。结构型指令可能会对宿主元素及其子元素做很复杂的事。当两个指令放在同一个元素上时,谁先谁后?NgIf 优先还是 NgFor 优先?NgIf可以取消 NgFor 的效果吗? 如果要这样做,Angular 应该如何把这种能力泛化,以取消其它结构型指令的效果呢?

对这些问题,没有办法简单回答。而禁止多个结构型指令则可以简单地解决这个问题。 这种情况下有一个简单的解决方案:把 *ngIf 放在一个"容器"元素上,再包装进 *ngFor 元素。 这个元素可以使用ng-container,以免引入一个新的 HTML 层级。

NgSwitch 内幕

Angular 的 NgSwitch 实际上是一组相互合作的指令:NgSwitchNgSwitchCaseNgSwitchDefault

例子如下:

src/app/app.component.html (ngswitch)

content_copy<div [ngSwitch]="hero?.emotion">
  <app-happy-hero    *ngSwitchCase="'happy'"    [hero]="hero"></app-happy-hero>
  <app-sad-hero      *ngSwitchCase="'sad'"      [hero]="hero"></app-sad-hero>
  <app-confused-hero *ngSwitchCase="'app-confused'" [hero]="hero"></app-confused-hero>
  <app-unknown-hero  *ngSwitchDefault           [hero]="hero"></app-unknown-hero>
</div>

一个值(hero.emotion)被被赋值给了 NgSwitch,以决定要显示哪一个分支。

NgSwitch 本身不是结构型指令,而是一个属性型指令,它控制其它两个 switch 指令的行为。 这也就是为什么你要写成 [ngSwitch] 而不是 *ngSwitch 的原因。

NgSwitchCaseNgSwitchDefault 都是结构型指令。 因此你要使用星号(*)前缀来把它们附着到元素上。 NgSwitchCase 会在它的值匹配上选项值的时候显示它的宿主元素。 NgSwitchDefault 则会当没有兄弟 NgSwitchCase 匹配上时显示它的宿主元素。

指令所在的元素就是它的宿主元素。 <happy-hero>*ngSwitchCase 的宿主元素。 <unknown-hero>*ngSwitchDefault 的宿主元素。

像其它的结构型指令一样,NgSwitchCaseNgSwitchDefault 也可以解开语法糖,变成 <ng-template> 的形式。

src/app/app.component.html (ngswitch-template)

content_copy<div [ngSwitch]="hero?.emotion">
  <ng-template [ngSwitchCase]="'happy'">
    <app-happy-hero [hero]="hero"></app-happy-hero>
  </ng-template>
  <ng-template [ngSwitchCase]="'sad'">
    <app-sad-hero [hero]="hero"></app-sad-hero>
  </ng-template>
  <ng-template [ngSwitchCase]="'confused'">
    <app-confused-hero [hero]="hero"></app-confused-hero>
  </ng-template >
  <ng-template ngSwitchDefault>
    <app-unknown-hero [hero]="hero"></app-unknown-hero>
  </ng-template>
</div>

优先使用星号(*)语法

星号(*)语法比不带语法糖的形式更加清晰。 如果找不到单一的元素来应用该指令,可以使用<ng-container>作为该指令的容器。

虽然很少有理由在模板中使用结构型指令的属性形式和元素形式,但这些幕后知识仍然是很重要的,即:Angular 会创建 <ng-template>,还要了解它的工作原理。 当需要写自己的结构型指令时,你就要使用 <ng-template>

<ng-template>指令

<ng-template>是一个 Angular 元素,用来渲染 HTML。 它永远不会直接显示出来。 事实上,在渲染视图之前,Angular 会把 <ng-template> 及其内容替换为一个注释。

如果没有使用结构型指令,而仅仅把一些别的元素包装进 <ng-template>中,那些元素就是不可见的。 在下面的这个短语"Hip! Hip! Hooray!"中,中间的这个 "Hip!"(欢呼声) 就是如此。

src/app/app.component.html (template-tag)

content_copy<p>Hip!</p>
<ng-template>
  <p>Hip!</p>
</ng-template>
<p>Hooray!</p>

Angular 抹掉了中间的那个 "Hip!" ,让欢呼声显得不再那么热烈了。

结构型指令

结构型指令会让 <ng-template> 正常工作,在你写自己的结构型指令时就会看到这一点。

使用<ng-container>把一些兄弟元素归为一组

通常都要有一个元素作为结构型指令的数组。 列表元素(<li>)就是一个典型的供 NgFor 使用的宿主元素。

src/app/app.component.html (ngfor-li)

content_copy<li *ngFor="let hero of heroes">{{hero.name}}</li>

当没有这样一个单一的宿主元素时,你就可以把这些内容包裹在一个原生的 HTML 容器元素中,比如 <div>,并且把结构型指令附加到这个"包裹"上。

src/app/app.component.html (ngif)

content_copy<div *ngIf="hero" class="name">{{hero.name}}</div>

但引入另一个容器元素(通常是 <span><div>)来把一些元素归到一个单一的根元素下,通常也会带来问题。注意,是"通常"而不是"总会"。

这种用于分组的元素可能会破坏模板的外观表现,因为 CSS 的样式既不曾期待也不会接受这种新的元素布局。 比如,假设你有下列分段布局。

src/app/app.component.html (ngif-span)

content_copy<p>
  I turned the corner
  <span *ngIf="hero">
    and saw {{hero.name}}. I waved
  </span>
  and continued on my way.
</p>

而你的 CSS 样式规则是应用于 <p> 元素下的 <span> 的。

src/app/app.component.css (p-span)

content_copyp span { color: red; font-size: 70%; }

这样渲染出来的段落就会非常奇怪。

结构型指令

本来为其它地方准备的 p span 样式,被意外的应用到了这里。

另一个问题是:有些 HTML 元素需要所有的直属下级都具有特定的类型。 比如,<select> 元素要求直属下级必须为 <option>,那就没办法把这些选项包装进 <div><span> 中。

如果这样做:

src/app/app.component.html (select-span)

content_copy<div>
  Pick your favorite hero
  (<label><input type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
</div>
<select [(ngModel)]="hero">
  <span *ngFor="let h of heroes">
    <span *ngIf="showSad || h.emotion !== 'sad'">
      <option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
    </span>
  </span>
</select>

下拉列表就是空的。

结构型指令

浏览器不会显示 <span> 中的 <option>

<ng-container> 的救赎

Angular 的 <ng-container> 是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。

下面是重新实现的条件化段落,这次使用 <ng-container>

src/app/app.component.html (ngif-ngcontainer)

content_copy<p>
  I turned the corner
  <ng-container *ngIf="hero">
    and saw {{hero.name}}. I waved
  </ng-container>
  and continued on my way.
</p>

这次就渲染对了。

结构型指令

现在用 <ng-container> 来根据条件排除选择框中的某个 <option>

src/app/app.component.html (select-ngcontainer)

content_copy<div>
  Pick your favorite hero
  (<label><input type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
</div>
<select [(ngModel)]="hero">
  <ng-container *ngFor="let h of heroes">
    <ng-container *ngIf="showSad || h.emotion !== 'sad'">
      <option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
    </ng-container>
  </ng-container>
</select>

下拉框也工作正常。

结构型指令

<ng-container> 是一个由 Angular 解析器负责识别处理的语法元素。 它不是一个指令、组件、类或接口,更像是 JavaScript 中 if 块中的花括号。

content_copyif (someCondition) {
  statement1;
  statement2;
  statement3;
}

没有这些花括号,JavaScript 只会执行第一句,而你原本的意图是把其中的所有语句都视为一体来根据条件执行。 而 <ng-container> 满足了 Angular 模板中类似的需求。

写一个结构型指令

在本节中,你会写一个名叫 UnlessDirective 的结构型指令,它是 NgIf 的反义词。 NgIf 在条件为 true 的时候显示模板内容,而 UnlessDirective则会在条件为 false 时显示模板内容。

src/app/app.component.html (appUnless-1)

content_copy<p *appUnless="condition">Show this sentence unless the condition is true.</p>

创建指令很像创建组件。

  • 导入 Directive 装饰器(而不再是 Component)。
  • 导入符号 InputTemplateRefViewContainerRef,你在任何结构型指令中都会需要它们。
  • 给指令类添加装饰器。
  • 设置 CSS 属性选择器 ,以便在模板中标识出这个指令该应用于哪个元素。

这里是起点:

src/app/unless.directive.ts (skeleton)

content_copyimport { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
}

指令的选择器通常是把指令的属性名括在方括号中,如 [appUnless]。 这个方括号定义出了一个 CSS 属性选择器。

该指令的属性名应该拼写成小驼峰形式,并且带有一个前缀。 但是,这个前缀不能用 ng,因为它只属于 Angular 本身。 请选择一些简短的,适合你自己或公司的前缀。 在这个例子中,前缀是 my

指令的类名Directive 结尾,参见风格指南。 但 Angular 自己的指令例外。

TemplateRefViewContainerRef

像这个例子一样的简单结构型指令会从 Angular 生成的 <ng-template> 元素中创建一个内嵌的视图,并把这个视图插入到一个视图容器中,紧挨着本指令原来的宿主元素 <p>(译注:注意不是子节点,而是兄弟节点)。

你可以使用TemplateRef取得 <ng-template> 的内容,并通过ViewContainerRef来访问这个视图容器

你可以把它们都注入到指令的构造函数中,作为该类的私有属性。

src/app/unless.directive.ts (ctor)

content_copyconstructor(
  private templateRef: TemplateRef<any>,
  private viewContainer: ViewContainerRef) { }

appUnless 属性

该指令的使用者会把一个 true/false 条件绑定到 [appUnless] 属性上。 也就是说,该指令需要一个带有 @InputappUnless 属性。

要了解关于 @Input 的更多知识,参见模板语法一章。

src/app/unless.directive.ts (set)

content_copy@Input() set appUnless(condition: boolean) {
  if (!condition && !this.hasView) {
    this.viewContainer.createEmbeddedView(this.templateRef);
    this.hasView = true;
  } else if (condition && this.hasView) {
    this.viewContainer.clear();
    this.hasView = false;
  }
}

一旦该值的条件发生了变化,Angular 就会去设置 appUnless 属性。因为不能用 appUnless 属性,所以你要为它定义一个设置器(setter)。

  • 如果条件为假,并且以前尚未创建过该视图,就告诉视图容器(ViewContainer)根据模板创建一个内嵌视图
  • 如果条件为真,并且视图已经显示出来了,就会清除该容器,并销毁该视图。

没有人会读取 appUnless 属性,因此它不需要定义 getter。

完整的指令代码如下:

src/app/unless.directive.ts (excerpt)

content_copyimport { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

/**
 * Add the template content to the DOM unless the condition is true.
 */
@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
  private hasView = false;

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef) { }

  @Input() set appUnless(condition: boolean) {
    if (!condition && !this.hasView) {
      this.viewContainer.createEmbeddedView(this.templateRef);
      this.hasView = true;
    } else if (condition && this.hasView) {
      this.viewContainer.clear();
      this.hasView = false;
    }
  }
}

把这个指令添加到 AppModule 的 declarations 数组中。

然后创建一些 HTML 来试用一下。

src/app/app.component.html (appUnless)

content_copy<p *appUnless="condition" class="unless a">
  (A) This paragraph is displayed because the condition is false.
</p>

<p *appUnless="!condition" class="unless b">
  (B) Although the condition is true,
  this paragraph is displayed because appUnless is set to false.
</p>

conditionfalse 时,顶部的段落就会显示出来,而底部的段落消失了。 当 conditiontrue 时,顶部的段落被移除了,而底部的段落显示了出来。

结构型指令

小结

你可以去在线例子 / 下载范例中下载本章的源码。

本章相关的代码如下:

app.component.ts

app.component.html

app.component.css

app.module.ts

hero.ts

hero-switch.components.ts

unless.directive.ts

content_copyimport { Component } from '@angular/core'; import { Hero, heroes } from './hero'; @Component({  selector: 'app-root',  templateUrl: './app.component.html',  styleUrls: [ './app.component.css' ]})export class AppComponent {  heroes = heroes;  hero = this.heroes[0];   condition = false;  logs: string[] = [];  showSad = true;  status = 'ready';   trackById(index: number, hero: Hero): number { return hero.id; }}

你学到了

  • 结构型指令可以操纵 HTML 的元素布局。
  • 当没有合适的容器元素时,可以使用<ng-container>对元素进行分组。
  • Angular 会把星号(*)语法解开成 <ng-template>
  • 内置指令 NgIfNgForNgSwitch 的工作原理。
  • 微语法如何展开成<ng-template>
  • 写了一个自定义结构型指令 —— UnlessDirective
AngularJS

Angular 是一个开发平台。它能帮你更轻松的构建 Web 应用。Angular 集声明式模板、依赖注入、端到端工具和一些最佳实践于一身,为你解决开发方面的各种挑战。

AngularJS目录

1.快速上手 | quick start
2.语言服务
3.安全
4.环境准备与部署
5.Service Worker
6.保持最新
7.从 AngularJS 升级
8.服务端渲染
9.Visual Studio 2015 快速上手
10.风格指南
11.国际化
12.测试
13.路由与导航
14. 教程 | Tutorial
15.架构
16.组件与模板
17.表单
18.可观察对象与RxJS
19.引导启动
20.Angular 模块
21.依赖注入
22.HttpClient
23.词汇表
24.AngularJS 应用
25.AngularJS 模块
26.AngularJS 事件
27.AngularJS HTML DOM
28.AngularJS 过滤器
29.AngularJS 控制器
30.AngularJS 指令
31.AngularJS 表达式
32.AngularJS 简介
33.AngularJS 参考手册
34.AngularJS 实例
35.AngularJS 输入验证
36.AngularJS 表单
37.AngularJS SQL
38.AngularJS 表格
39.AngularJS Http
40.AngularJS 包含
41.AngularJS Bootstrap
42.AngularJS API
43.AngularJS ng-checked 指令
44.AngularJS ng-change 指令
45.AngularJS ng-blur 指令
46.AngularJS ng-bind-template 指令
47.AngularJS ng-bind-html 指令
48.AngularJS ng-bind 指令
49.AngularJS ng-app 指令
50.AngularJS Scope(作用域)
51.AngularJS ng-model 指令
52.AngularJS ng-dblclick 指令
53.AngularJS ng-cut 指令
54.AngularJS ng-csp 指令
55.AngularJS ng-copy 指令
56.AngularJS ng-controller 指令
57.AngularJS ng-cloak 指令
58.AngularJS ng-click 指令
59.AngularJS ng-class-odd 指令
60.AngularJS ng-class-even 指令
61.AngularJS ng-class 指令
62.AngularJS ng-keyup 指令
63.AngularJS ng-keypress 指令
64.AngularJS ng-keydown 指令
65.AngularJS ng-init 指令
66.AngularJS ng-include 指令
67.AngularJS ng-if 指令
68.AngularJS ng-href 指令
69.AngularJS ng-hide 指令
70.AngularJS ng-focus 指令
71.AngularJS ng-disabled 指令
72.AngularJS ng-non-bindable 指令
73.AngularJS ng-mouseup 指令
74.AngularJS ng-mouseover 指令
75.AngularJS ng-mousemove 指令
76.AngularJS ng-mouseleave 指令
77.AngularJS ng-mouseenter 指令
78.AngularJS ng-mousedown 指令
79.AngularJS ng-model-options 指令
80.AngularJS ng-model 指令
81.AngularJS ng-list 指令
82.AngularJS ng-style 指令
83.AngularJS ng-srcset 指令
84.AngularJS ng-src 指令
85.AngularJS ng-show 指令
86.AngularJS ng-selected 指令
87.AngularJS ng-repeat 指令
88.AngularJS ng-readonly 指令
89.AngularJS ng-paste 指令
90.AngularJS ng-options 指令
91.AngularJS ng-open 指令
92.AngularJS ng-value 指令
93.AngularJS ng-switch 指令
94.AngularJS ng-submit 指令
95.AngularJS 服务(Service)
96.AngularJS Select(选择框)
97.AngularJS 动画
98.AngularJS 依赖注入