针对业务需要,整个流程为点击按钮=>调取异步方法=>设置操作状态=>异步结束,重置状态;其中调取异步方法中,点击按钮时都无效或不可点击

将业务封装自定义指令,通过点击按钮后监听事件,在DOM上设置属性来判断本次点击事件时的状态,但次方法对于多层DOM结构时会出现一些致命BUG导致无法生效,所以这里采用定义状态变量的方法实现,


1.首先可以通过自定义指令的监听事件来监听整个点击事件,点击后可以通过设置变量的方法,来维护按钮的状态;

type Processing = 'processing';
type Initial = 'initial';
type StatusType = Processing | Initial;

@Directive({
selector: '[actionDelegate]',
host: {
'[attr.disabled]': 'disabled||null',
},
exportAs: 'actionDelegate',
})
export class ActionDelegateDirective{
@Input() action: (params?: unknown) => Promise<string> | void = () => {}; //业务函数

@Input() actionDelegateParams: unknown = {}; //业务函数的参数

@Input() actionDelegateInnerHTML = ''; //异步操作过程中DOM内容

@Input() disabled = false;

status: StatusType = 'initial';
@HostListener('click', ['$event','$event.target'])
onClick(event: MouseEvent): void {

}
}

2.将业务函数封装为一个Promise函数传入并执行,通过函数的返回结果来判断当前异步请求的状态

type Processing = 'processing';
type Initial = 'initial';
type StatusType = Processing | Initial;

@Directive({
selector: '[actionDelegate]',
host: {
'[attr.disabled]': 'disabled||null',
},
exportAs: 'actionDelegate',
})
export class ActionDelegateDirective {
@Input() action: (params?: unknown) => Promise<string> | void = () => {};

@Input() actionDelegateParams: unknown = {};

@Input() actionDelegateInnerHTML = '';

@Input() disabled = false;

status: StatusType = 'initial';

@HostListener('click', ['$event','$event.target'])
onClick(event: MouseEvent): void {

if (this.status === 'processing') {
return;
}

//执行业务函数
const returnValue = this.action(this.actionDelegateParams);


//判断返回的结果,是否存在于Promise的原型链上
if (returnValue && returnValue instanceof Promise) {
const originInnerHTML = target.innerHTML;

this.disabled = true;
this.status = 'processing';

if (this.actionDelegateInnerHTML) {
target.innerHTML = this.actionDelegateInnerHTML;
}

returnValue.then(
() => {
this.status = 'initial';
this.disabled = false;
if (this.actionDelegateInnerHTML) {
target.innerHTML = originInnerHTML;
}
},
() => {
this.status = 'initial';
this.disabled = false;
if (this.actionDelegateInnerHTML) {
target.innerHTML = originInnerHTML;
}
}
);
}
}

阻止冒泡

@HostListener('click', ['$event'])
onClick(event: MouseEvent): void {
if (event) {
event.preventDefault();
}

...
}

实际使用,例:

 handleConfirm = (): Promise<string> | void => 
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 5 * 1000);
});

<button actionDelegate [action]="handleSendVerifyCode">发送验证码</button>