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 相关文章推荐
改善用户体验的五款jQuery插件分享
May 22 Javascript
使用原生JS实现弹出层特效
Dec 22 Javascript
jQuery实现简单隔行变色的方法
Feb 20 Javascript
EasyUi 打开对话框后控件赋值及赋值后不显示的问题解决办法
Jan 19 Javascript
新手vue构建单页面应用实例代码
Sep 18 Javascript
移动端效果之IndexList详解
Oct 20 Javascript
详解基于Vue+Koa的pm2配置
Oct 24 Javascript
浅谈node中的cluster集群
Jun 02 Javascript
微信小程序绑定手机号获取验证码功能
Oct 22 Javascript
小程序实现图片预览裁剪插件
Nov 22 Javascript
基于js实现的图片拖拽排序源码实例
Nov 04 Javascript
关于Vue中$refs的探索浅析
Nov 05 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对gzip文件或者字符串解压实例参考
2008/07/25 PHP
国外十大最流行的PHP框架排名
2013/07/04 PHP
php curl中gzip的压缩性能测试实例分析
2016/11/08 PHP
php+jQuery实现的三级导航栏下拉菜单显示效果
2017/08/10 PHP
php实现生成PDF文件的方法示例【基于FPDF类库】
2018/07/21 PHP
Extjs中使用extend(js继承) 的代码
2012/03/15 Javascript
原生js仿jq判断当前浏览器是否为ie,精确到ie6~8
2014/08/30 Javascript
JavaScript小技巧整理篇(非常全)
2016/01/26 Javascript
关于js二维数组和多维数组的定义声明(详解)
2016/10/02 Javascript
Angular动态添加、删除输入框并计算值实例代码
2017/03/29 Javascript
vue分类筛选filter方法简单实例
2017/03/30 Javascript
nginx+vue.js实现前后端分离的示例代码
2018/02/12 Javascript
koa-router源码学习小结
2018/09/07 Javascript
vue实现Excel文件的上传与下载功能的两种方式
2019/06/28 Javascript
关于JS解构的5种有趣用法
2019/09/05 Javascript
关于layui 弹出层一闪而过就消失的解决方法
2019/09/09 Javascript
javascript实现画板功能
2020/04/12 Javascript
[47:12]TFT vs Secret Supermajor小组赛C组 BO3 第三场 6.3
2018/06/04 DOTA
Python的迭代器和生成器使用实例
2015/01/14 Python
python的mysqldb安装步骤详解
2017/08/14 Python
用python爬取租房网站信息的代码
2018/12/14 Python
浅谈python3.6的tkinter运行问题
2019/02/22 Python
python读取文件指定行内容实例讲解
2020/03/02 Python
django 模版关闭转义方式
2020/05/14 Python
用python打开摄像头并把图像传回qq邮箱(Pyinstaller打包)
2020/05/17 Python
详解Selenium-webdriver绕开反爬虫机制的4种方法
2020/10/28 Python
ONLY德国官方在线商店:购买时尚女装
2017/09/21 全球购物
巴西购物网站:Onofre Agora
2020/06/08 全球购物
三年级数学教学反思
2014/01/31 职场文书
低碳环保倡议书
2014/04/14 职场文书
投标承诺书怎么写
2014/05/24 职场文书
会计专业自荐书
2014/07/08 职场文书
旅游局领导班子“四风”问题对照检查材料思想汇报
2014/09/29 职场文书
思想道德自我评价2015
2015/03/09 职场文书
结婚主持人致辞
2015/07/28 职场文书
关于redisson缓存序列化几枚大坑说明
2021/08/04 Redis