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 相关文章推荐
Javascript调试工具(下载)
Jan 09 Javascript
js 动态修改css文件用到了cssRule
Aug 20 Javascript
JavaScript中神奇的call()方法
Mar 12 Javascript
简单分析javascript面向对象与原型
May 21 Javascript
基于JavaScript将表单序列化类型的数据转化成对象的处理(允许对象中包含对象)
Dec 28 Javascript
利用JS实现点击按钮后图片自动切换的简单方法
Oct 24 Javascript
JS实现的表头列头固定页面功能示例
Jan 10 Javascript
详解小程序设置缓存并且不覆盖原有数据
Apr 15 Javascript
从零使用TypeScript开发项目打包发布到npm
Feb 14 Javascript
如何用JS实现网页瀑布流布局
Apr 24 Javascript
threejs太阳光与阴影效果实例代码
Apr 05 Javascript
vue2的 router在使用过程中遇到的一些问题
Apr 13 Vue.js
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递归列出所有文件和目录的代码
2008/09/10 PHP
无法在发生错误时创建会话,请检查 PHP 或网站服务器日志,并正确配置 PHP 安装(win+linux)
2012/05/05 PHP
ThinkPHP3.1新特性之查询条件预处理简介
2014/06/19 PHP
PHP将字符分解为多个字符串的方法
2014/11/22 PHP
PHP模板引擎Smarty内建函数详解
2016/04/11 PHP
Laravel框架分页实现方法分析
2018/06/12 PHP
总结PHP中初始化空数组的最佳方法
2019/02/13 PHP
Lazy Load 延迟加载图片的 jQuery 插件
2010/02/06 Javascript
原生js编写设为首页兼容ie、火狐和谷歌
2014/06/05 Javascript
JS中的Replace方法使用经验分享
2015/05/20 Javascript
jQuery实现浮动层随浏览器滚动条滚动的方法
2015/09/22 Javascript
js判断当前页面用什么浏览器打开的方法
2016/01/06 Javascript
Jquery ui datepicker设置日期范围,如只能隔3天【实现代码】
2016/05/04 Javascript
相册展示PhotoSwipe.js插件实现
2016/08/25 Javascript
jQuery-mobile事件监听与用法详解
2016/11/23 Javascript
利用Plupload.js解决大文件上传问题, 带进度条和背景遮罩层
2017/03/15 Javascript
jQuery插件select2利用ajax高效查询大数据列表(可搜索、可分页)
2017/05/19 jQuery
vue父组件点击触发子组件事件的实例讲解
2018/02/08 Javascript
让你5分钟掌握9个JavaScript小技巧
2018/06/09 Javascript
解析原来浏览器原生支持JS Base64编码解码
2019/08/12 Javascript
适合前端Vue开发童鞋的跨平台Weex的使用详解
2019/10/16 Javascript
基于原生js实现九宫格算法代码实例
2020/07/03 Javascript
修改NPM全局模式的默认安装路径的方法
2020/12/15 Javascript
Python设计模式之门面模式简单示例
2018/01/09 Python
基于python-pptx库中文文档及使用详解
2020/02/14 Python
HTML5之SVG 2D入门2—图形绘制(基本形状)介绍及使用
2013/01/30 HTML / CSS
英国儿童设计师服装和玩具购物网站:Zac & Lulu
2020/10/19 全球购物
物流仓管员工作职责
2014/01/06 职场文书
酒店采购员岗位职责
2014/03/14 职场文书
保密承诺书范文
2014/03/27 职场文书
校长师德表现自我评价
2015/03/05 职场文书
2015年关爱留守儿童工作总结
2015/05/22 职场文书
初中政治教学反思
2016/02/23 职场文书
详解Apache SkyWalking 告警配置指南
2021/04/22 Servers
深入讲解Vue中父子组件通信与事件触发
2022/03/22 Vue.js
GoFrame gredis缓存DoVar Conn连接对象 自动序列化GoFrame gredisDo/DoVar方法Conn连接对象自动序列化/反序列化总结
2022/06/14 Golang