Angular 与 Vue 除了内置的一系列指令之外,它们还允许你注册自定义的指令 。自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑。
为了更好的做比较,我们还是按照 Angular 中创建属性型指令与结构型指令做为比较的基准。
创建属性型指令
我们将创建一个高亮指令,该指令将宿主元素的背景颜色设置为黄色。
Angular
创建
在 Angular中,@Directive()
装饰器的配置属性指定了该指令的 CSS 属性 Attribute 选择器 [appHighlight]
。
在指令的 constructor()
中添加 ElementRef
,以便注入对宿主 DOM 元素的引用,即你应用 appHighlight
的元素。
import {Directive, ElementRef, inject} from '@angular/core';
@Directive({
selector: '[appHighlight]',
})
export class HighlightDirective {
private el = inject(ElementRef);
constructor() {
this.el.nativeElement.style.backgroundColor = 'yellow';
}
}
应用
Angular 创建 HighlightDirective
类的实例,并将对 <p>
元素的引用注入到该指令的构造函数中,构造函数会将 <p>
元素的背景样式设置为黄色。
<p appHighlight>Highlight me!</p>
Vue
创建
一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数:
<script setup>
// 在模板中启用 v-highlight
const vHighlight = {
mounted: (el) => {
el.classList.add('is-highlight')
}
}
</script>
应用
当 Vue 将元素插入到 DOM 中后,该指令会将一个 class 添加到元素中:
<template>
<p v-highlight>This sentence is important!</p>
</template>
React
React 中并没有指令这一概念,可以使用自定义Hook + 组件来实现指定的效果。具体实现过程这里不再列举。
创建结构型指令
在 Angular 中结构型指令是应用于 <ng-template>
元素的指令,它们有条件地或重复地渲染 <ng-template>
的内容。
Vue 中很少用到自定义结构型指令,在 Vue 中结构型指令主要是使用 JS 来对 Dom 进行操作,系统本身并没有做过多的封装,React 中亦是如此。
这里主要通过 Angular 创建一个指令来了解结构型指令的概念。该指令从给定的数据源获取数据,并在数据可用时渲染其模板。这个指令被称为 SelectDirective
,以 SQL 关键字 SELECT
命名,并使用属性选择器 [select]
与之匹配。
Angular
创建
Angular 创建指令类并指定 CSS 选择器 [select]
,该选择器在模板中标识该指令。导入 TemplateRef
和 ViewContainerRef
。在指令中注入 TemplateRef
和 ViewContainerRef
作为私有属性。
import {Directive, TemplateRef, ViewContainerRef} from '@angular/core';
@Directive({
selector: '[select]',
})
export class SelectDirective {
private templateRef = inject(TemplateRef);
private ViewContainerRef = inject(ViewContainerRef);
}
添加一个 selectFrom
@Input()
属性。
export class SelectDirective {
// ...
@Input({required: true}) selectFrom!: DataSource;
}
现在 SelectDirective
已被搭建为具有输入的结构型指令,你现在可以添加逻辑来获取数据并使用它渲染模板:
export class SelectDirective {
// ...
async ngOnInit() {
const data = await this.selectFrom.load();
this.viewContainerRef.createEmbeddedView(this.templateRef, {
// Create the embedded view with a context object that contains
// the data via the key `$implicit`.
$implicit: data,
});
}
}
应用
假设我们有以下数据源:
// 数据源定义
const source = {
async load() {
// 模拟API请求延迟
await new Promise(resolve => setTimeout(resolve, 1000));
return {
id: 123,
name: "Angular Guide",
author: "Dev Team"
};
}
};
使用指令:
<p *select="let data from source" class="data-view">
The data is: {{ data.name }} by {{ data.author }}
</p>
Vue
在 Vue 中很少用到自定义结构型指令,由于系统并没有对指令相关层面做过多的封装,如果要自定义结构型指令是基于 js 对 Dom 来操作。这里就不再列举示例。
React
React 中并没有指令这一概念,可以使用自定义Hook + 组件来实现指定的效果。具体实现过程这里不再列举。
小结
Angular 对于指令的封装更多一些,Vue 中的自定义指令常见于属性型指令,结构性的指令更多的是基于第三方库的调用而封装。React 则还是以自定义Hook + 组件来实现任何的指令操作。
本篇介绍的是如何创建自定义指令,是基于Angular的标准来进行的比较。
文章参考链接:
发表回复