针对业务需要,整个流程为点击按钮=>调取异步方法=>设置操作状态=>异步结束,重置状态
;其中调取异步方法中,点击按钮时都无效或不可点击
将业务封装自定义指令,通过点击按钮后监听事件,在DOM上设置属性来判断本次点击事件时的状态,但次方法对于多层DOM结构时会出现一些致命BUG导致无法生效,所以这里采用定义状态变量的方法实现,
1.首先可以通过自定义指令的监听事件来监听整个点击事件,点击后可以通过设置变量的方法,来维护按钮的状态;
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
| 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函数传入并执行,通过函数的返回结果来判断当前异步请求的状态
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| 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; } } ); } }
|
阻止冒泡
1 2 3 4 5 6 7 8
| @HostListener('click', ['$event']) onClick(event: MouseEvent): void { if (event) { event.preventDefault(); } ... }
|
实际使用,例:
1 2 3 4 5 6 7 8
| handleConfirm = (): Promise<string> | void => new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); }, 5 * 1000); });
<button actionDelegate [action]="handleSendVerifyCode">发送验证码</button>
|