Angular 2.x学习教程之结构指令详解


Posted in Javascript onMay 25, 2017

结构指令是什么

结构指令通过添加和删除 DOM 元素来更改 DOM 布局。Angular 中两个常见的结构指令是 *ngIf*ngFor

了解 * 号语法

* 号是语法糖,用于避免使用复杂的语法。我们以 *ngIf 指令为例:

Angular 2.x学习教程之结构指令详解

(图片来源:https://netbasal.com/)

  • Angular 把 host (宿主元素) 包装在 template 标签里面
  • Angular 将 ngIf 转换为属性绑定 - [ngIf]

创建结构指令

首先,让我们了解如何创建一个结构指令。 接下来我们将要实现一个简单的 ngIf 指令。

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

@Directive({ selector: '[myNgIf]'})
export class MyNgIfDirective {

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

 @Input() set myNgIf(condition: boolean) {
 if (condition) {
  this.viewContainer.createEmbeddedView(this.templateRef);
 } else {
  this.viewContainer.clear();
 }
 }
}

我们可以按照以下方式使用我们的指令:

<div *myNgIf=”condition”></div>

下面我们来解释一下上面的代码。

TemplateRef

如名字所示,TemplateRef 用于表示模板的引用。

Angular 2.x学习教程之结构指令详解

(图片来源:https://netbasal.com/)

ViewContainerRef

正如上面介绍的,模板中包含了 DOM 元素,但如果要显示模板中定义的元素,我们就需要定义一个插入模板中元素的地方。在 Angular 中,这个地方被称作容器,而 ViewContainerRef 用于表示容器的引用。那什么元素会作为容器呢?

Angular 将使用 comment 元素替换 template 元素,作为视图容器。

我们来看一个具体的示例:

@Component({
 selector: 'my-app',
 template: `
 <div>
  <h2 *myNgIf="condition">Hello {{name}}</h2>
  <button (click)="condition = !condition">Click</button>
 </div>
 `,
})
export class App {
 name: string;
 condition: boolean = false;
 constructor() {
 this.name = 'Angular2'
 }
}

以上代码成功运行后,浏览器的显示内容如下:

Angular 2.x学习教程之结构指令详解

(图片来源:https://netbasal.com/)

ViewContainerRef 对象提供了 createEmbeddedView() 方法,该方法接收 TemplateRef 对象作为参数,并将模板中的内容作为容器 (comment 元素) 的兄弟元素,插入到页面中。

现在,你已经了解如何创建结构指令,接下来让我们看看两个具体的实例。

基于用户角色显示不同的内容

指令定义

@Directive({selector: '[ifRole]'})
export class IfRoleDirective {
 user$ : Subscription;
 @Input("ifRole") roleName : string;

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

 ngOnInit() {
 this.user$ = this.authService.user
  .do(() => this.viewContainer.clear())
  .filter(user => user.role === this.roleName)
  .subscribe(() => {
  this.viewContainer.createEmbeddedView(this.templateRef);
  });
 }

 ngOnDestroy() {
 this.user$.unsubscribe();
 }
}

指令应用

<div *ifRole="'admin'">
 Only for Admin
</div>

<div *ifRole="'client'">
 Only for Client
</div>

<div *ifRole="'editor'">
 Only for Editor
</div>

创建 Range 指令

指令定义

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

@Directive({
 selector: '[range]'
})
export class RangeDirective {
 _range: number[];

 @Input()
 set range(value: number) {
  this.vcr.clear();
  this._range = this.generateRange(value[0], value[1]);
  this._range.forEach(num => {
   this.vcr.createEmbeddedView(this.tpl, {
    $implicit: num
   });
  });
 }

 constructor(
  private vcr: ViewContainerRef,
  private tpl: TemplateRef<any>) { }

 private generateRange(from: number, to: number): number[] {
  var numbers: number[] = [];
  for (let i = from; i <= to; i++) {
   numbers.push(i);
  }
  return numbers;
 }
}

以上示例中,我们在调用 createEmbeddedView() 方法时,设置了第二个参数 {$implicit: num}  。Angular 为我们提供了 let 模板语法,允许在生成上下文时定义和传递上下文。

这将允许我们引用 *range="[20,30]; let num" 模板中声明的变量。我们使用 $implicit 名称,因为我们不知道用户在使用这个指令时,会使用什么名字。

Angular 2.x学习教程之结构指令详解

(图片来源:https://netbasal.com/)

指令应用

<h1>Your age:</h1>
<select>
 <ng-container *range="[18, 80]; let num">
 <option [ngValue]="num">{{num}}</option>
 </ng-container>
</select>

<h1>Year:</h1>
<select>
 <ng-container *range="[1998, 2016]; let num">
 <option [ngValue]="num">{{num}}</option>
 </ng-container>
</select>

以上代码成功运行后,浏览器的显示内容如下:

Angular 2.x学习教程之结构指令详解

(图片来源:https://netbasal.com/)

总结

以上就是这篇文章的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
iframe的父子窗口之间的对象相互调用基本用法
Sep 03 Javascript
JQueryiframe页面操作父页面中的元素与方法(实例讲解)
Nov 19 Javascript
jQuery异步验证用户名是否存在示例代码
May 21 Javascript
innerHTML属性,outerHTML属性,textContent属性,innerText属性区别详解
Mar 13 Javascript
JavaScript原生对象之Number对象的属性和方法详解
Mar 13 Javascript
jquery实现简单的自动播放幻灯片效果
Jun 13 Javascript
Node.js的MongoDB驱动Mongoose基本使用教程
Mar 01 Javascript
jQuery中DOM节点删除之empty与remove
Jan 20 Javascript
js正则表达式验证表单【完整版】
Mar 06 Javascript
NProgress显示顶部进度条效果及使用详解
Sep 21 Javascript
解决vue项目F5刷新mounted里的函数不执行问题
Nov 05 Javascript
Vue-cli打包后如何本地查看的操作
Sep 02 Javascript
bootstrap动态添加面包屑(breadcrumb)及其响应事件的方法
May 25 #Javascript
js获取一组日期中最近连续的天数
May 25 #Javascript
AngularJs定时器$interval 和 $timeout详解
May 25 #Javascript
slideToggle+slideup实现手机端折叠菜单效果
May 25 #Javascript
Bootstrap实现的标签页内容切换显示效果示例
May 25 #Javascript
React-router中结合webpack实现按需加载实例
May 25 #Javascript
node.js操作mongodb简单示例分享
May 25 #Javascript
You might like
php把session写入数据库示例
2014/02/26 PHP
php跨站攻击实例分析
2014/10/28 PHP
PHP 常用时间函数资料整理
2016/10/22 PHP
php获取指定数量随机字符串的方法
2017/02/06 PHP
PHP 命名空间和自动加载原理与用法实例分析
2020/04/29 PHP
javascript实现划词标记+划词搜索功能
2007/03/06 Javascript
面向对象的编程思想在javascript中的运用上部
2009/11/20 Javascript
js下判断 iframe 是否加载完成的完美方法
2010/10/26 Javascript
ExtJS如何设置与获取radio控件的选取状态
2014/01/22 Javascript
jquery实现的鼠标下拉滚动置顶效果
2014/07/24 Javascript
jQuery函数map()和each()介绍及异同点分析
2014/11/08 Javascript
JavaScript设置body高度为浏览器高度的方法
2015/02/09 Javascript
JavaScript基于ajax编辑信息用法实例
2015/07/15 Javascript
CSS图片响应式 垂直水平居中
2015/08/14 Javascript
Jquery元素追加和删除的实现方法
2016/05/24 Javascript
js中常用的Tab切换效果(推荐)
2016/08/30 Javascript
jquery 手势密码插件
2017/03/17 Javascript
浅谈Node.js CVE-2017-14849 漏洞分析(详细步骤)
2017/11/10 Javascript
vue 2.1.3 实时显示当前时间,每秒更新的方法
2018/09/16 Javascript
Vue 第三方字体图标引入 Font Awesome的方法
2018/09/28 Javascript
使用JavaScript计算前一天和后一天的思路详解
2019/12/20 Javascript
[42:24]完美世界DOTA2联赛循环赛 LBZS vs DM BO2第一场 11.01
2020/11/02 DOTA
浅谈python为什么不需要三目运算符和switch
2016/06/17 Python
python爬取NUS-WIDE数据库图片
2016/10/05 Python
Python与Java间Socket通信实例代码
2017/03/06 Python
python使用turtle库绘制时钟
2020/03/25 Python
详解python3中的真值测试
2018/08/13 Python
pyhanlp安装介绍和简单应用
2019/02/22 Python
python json.dumps中文乱码问题解决
2020/04/01 Python
Python3爬虫关于识别检验滑动验证码的实例
2020/07/30 Python
收银员岗位职责
2014/02/07 职场文书
财政专业大学生职业生涯规划书
2014/09/17 职场文书
董事会决议范本
2015/07/01 职场文书
求职自荐信该如何书写?
2019/06/24 职场文书
微信小程序实现录音Record功能
2021/05/09 Javascript
详解NumPy中的线性关系与数据修剪压缩
2022/05/25 Python