ng2-attribute-directive

Attribute directive 可以改变 DOM 元素的行为或者表现。
本文中我们将
. 写一个 Attribute directive 来改变 DOM 的文本颜色
. 在模板中应用 Attribuet directive
. 对用户的事件做出响应
. 通过 数据绑定(data binding) 向 directive 中传递数据

directive 概述

Angular 中有三种 directive

  1. Component 组件
  2. Structural directive 结构化 directive
  3. Attribute directive 属性 directive

组件(Component),实际上是一个有模板的 directive。它是三种 directive 最普通的一个,在我们应用中写的最多。

结构化 directive (Structural directive),通过添加或者删除一些 DOM 元素来改变 DOM 的布局,NgForNgIf 就是最熟悉的两个例子。

属性 directive(Attribute directive),改变元素的展示方式和行为动作。例如内置的 NgStyle 指令,我们可以同时改变几个元素的样式(css)。


接下来完成一个 attribute directive, 通过这个指令来,当用户鼠标停在一个 DOM 元素的时候改变当前元素的背景颜色

通过 StyleBinding 这个内置的指令可以设置元素的背景

1
<p [style.background]='"green"'>绿色</p>

当让了,创建一个指令不会仅仅这么简单。我们还需要在用户鼠标悬停的时候,改变元素的背景来响应用户的操作。


创建一个简单的 attribute directive

一个 attribute 指令至少需要一个由 @Directive 装饰器注释的 controller class。@DIrective 装饰器内指定一个 选择器(css selector), 指令就是通过这个选择器来识别相应的 DOM 元素。这个 controller class 内实现了指令所需要的行为动作。

创建一个新的文件并命名为 color.directive.ts, 代码如下

1
2
3
4
5
6
7
8
9
10
11
import { Directive ,ElementRef, Input } from '@angular/core';

@Directive({
selector: '[color]' // css 选择器,可以匹配到 <p color> *** </p>
})

export class ColorDirective {
constructor(el: ElementRef) {
el.nativeElement.style.color = 'green';
}
}

首先我们从 Angular 库中引入了一些东西。例如 Directive 来创建 @Directive() 装饰器,把 ElementRef 注入到当前指令的构造函数(constructor)中,方便我们获得当前的 DOM 元素。

然后用一对象定义了指令的元数据(metadata)作为参数传入 @Directive 装饰器内。一个 @Directive 装饰器通常通过 css 属性选择器来和模板中的html元素建立关系,如 [color], Angular 将会定位到模板内所有包含 attribute 为 heiglight 的元素。

紧挨着装饰器下面,我们定义了一个 controller class 其内部包含了指令的相关逻辑。同时为了方便其他组件引用,我们把它导出(export)。

Angular 为定位到的每一个元素创建了指令(directive)的 controller class 实例,并且在构造函数中注入 Angular ElementRef。ElementRef 是一个 服务(service),我们通过它的 nativeElement 属性直接获取到 DOM 元素。然后我们就可以通过 DOM 元素的 style.backgroundColor 接口来设置元素的背景颜色。


如何使用 attribute directive

创建 app.component.html 文件,代码如下:

1
<p>尝试一下 attribute directive,这里是<span color>绿色文字</span></p>

创建 app.component.ts 文件,引入 app.component.html 模板文件,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Component } from '@angular/core';

import { ColorDirective } from './color.directive';

@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
directives: [ColorDirective]
})

export class AppComponent {
constructor(){}
}

用 import 引入我们的 ColorDirective class, 添加到当前的组件元数据(metadata)配置中, 这样 Anuglar 就可以识别出模板中我们定义了 color 属性的 span 元素。

具体效果相关源码
ColorDirective
来回顾一下 Angular 做了些什么,首先 Angular 定位到了包含 color 属性的元素,紧接着创建了 ColorDirective class 的实例,注入当前元素的引用(ElementRef),最后在构造函数中设置 <span> 元素的颜色为 green。

对用户的事件做出响应

我们不应仅限于简单的设置元素的颜色,指令也应该响应用户的事件,比如鼠标悬停的时候改变元素颜色。
我们需要
1 监听用户的鼠标移入移出动作
2 通过设置或还原元素的颜色来响应用户的动作

给指令的元数据(metadata)配置 host 属性,配置两个鼠标动作到指令内部的对应方法上。

1
2
3
4
host: {
'(mouseenter)': 'onMouseEnter()',
'(mouseleave)': 'onMouseLeave()'
}

host 属性可以匹配到 attribute 的宿主 DOM 元素的引用,例如上文中的 <span color>绿色文字</span>。如果用旧的语法,我们应该给 elementRef.nativeElement 添加事件。
但是这带来了新的问题
1 必须正确的添加事件监听(listeners)
2 当指令销毁的时候,需要手动取消事件(listeners)以便释放内存
3 需要直接与 DOM API 交互,手动操作 DOM。但是我们通常是避免直接操作 DOM
所以,Angular 提供了 host 来避免以上问题。

接下来,来实现刚才的两个鼠标事件

1
2
3
4
5
6
onMouseEnter() { this.setColor('yellow'); }
onMouseLeave() { this.setColor('green'); }

private setColor(color) {
this.el.style.color = color;
}

完整的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

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

@Directive({
selector: '[color]', // css 选择器,可以匹配到 <p color> *** </p>
host: {
'(mouseenter)': 'onMouseEnter()',
'(mouseleave)': 'onMouseLeave()'
}
})

export class ColorDirective {
private el: HTMLElement;

constructor(el: ElementRef) {
this.el = el.nativeElement;

this.el.style.color = 'green';
}

onMouseEnter() { this.setColor('yellow'); }
onMouseLeave() { this.setColor('green'); }

private setColor(color) {
this.el.style.color = color;
}
}

效果入下

通过 Input 绑定数据(data binding)

当前我们的 ColorDirective 的颜色是固定不变的,我们应该自定义初始化的颜色,如下:

1
<p color="myColor">第一个 directive</p>

升级当前的 ColorDirective,通过 Input 来获取外界的颜色值
最终代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { Directive ,ElementRef, Input } from '@angular/core';

@Directive({
selector: '[color]', // css 选择器,可以匹配到 <p color> *** </p>
host: {
'(mouseenter)': 'onMouseEnter()',
'(mouseleave)': 'onMouseLeave()'
}
})

export class ColorDirective {
private _defaultColor = 'yellow';
private el: HTMLElement;

@Input('color') myColor: string;

constructor(el: ElementRef) {
this.el = el.nativeElement;

this.el.style.color = this.myColor || this._defaultColor;
}

onMouseEnter() { this.setColor('yellow'); }
onMouseLeave() { this.setColor('green'); }

private setColor(color) {
this.el.style.color = color;
}
}

@Input 装饰器,通过 color 把元素的 color 属性值传递到 directive 中。与 myColor 绑定,当一个元素没有设置 color 值的时候,directive 会给默认给它设置成 yellow。

最终版的 app.component.html 模板文件:

1
2
3

<p>尝试一下 attribute directive,这里是<span [color]="appColor">绿色文字</span></p>
<button (click)="appColor = 'blue' ">切换</button>

[color]="appColor"中 appColor 是数据源,不需要主动声明;color 是数据绑定的目标,必须在 directive 中声明,否则报错。

弄了个hexo主题

博客又荒废好久了,貌似都没有认真写过。这几年也接触过不少博客系统,但是内容却没有沉淀下来。接触前端这些年也能力自己高了,基于 hexo 平台再次开张了。记录一些前端工作学习中的心得,也方便和大家交流

开始新的主题,也就是现在你看到的这个博客,github 地址 hexo-theme-kunl。 主题还在开发中,整体风格比较简洁,也木有太多的功能。慢慢打磨,不说成精品,自己看着顺眼吧。

git 常用命令整理

1
2
3
4
5
6
7
8
9
10
查看分支 git branch -a
创建分支 git branch name
切换分支 git checkout name
创建并切换 git checkout -b name
合并某个到当前 git merge name
删除分支 git branch -d name
提交分支 git push origin name

创建tag git tag name
创建并指定标签信息 git tag -a name -m ''

事件委托

###利用冒泡的原理,把事件添加到父级上,触发执行效果
1提高性能
2新添加的对象也有事件

event对象的事件源,任何事件中,被操作的事件对象。
    IE:event.srcElement
    w3c:event.target
    通过nodeName判断当前源的标签名