Angular 组件:禁用点击事件
Angular component: disable click event
我正在创建一个像这样的可重用组件:
<my-button [isDisabled]="isDisabled" (click)="click($event)"> submit </my-button>
我想在 属性 isDisabled 为 true 时禁用点击事件,我尝试过类似的方法但它不起作用。
packages/component/my-button.component.html
<button [disabled]="isDisabled" #myButton>
<ng-content></ng-content>
</button>
packages/component/my-button.component.ts
@ViewChild('uxButton') uxButton: ElementRef;
@Input() isDisabled: boolean = false;
this.myButton.nativeElement.parentNode.removeEventListener('click' , (e) => {
e.stopPropagation();
});
我们可以addeventlistener/remove根据需要使用ElementRef/HostListener,但简单的修复方法如下。
click(event) {
if (this.isDisabled) {
return;
}
......
}
这样试试
<button [disabled]="isDisabled" (click)="btnClick.emit($event)">
<ng-content></ng-content>
</button>
@Input() isDisabled: boolean = false;
@Output() btnClick = new EventEmitter();
使用 Output
并且默认情况下,如果按钮被禁用,按钮单击事件将不起作用。好好利用它
<my-button [isDisabled]="isDisabled" (btnClick)="click($event)"> submit </my-button>
我认为问题出在您的代码中:
<my-button [isDisabled]="isDisabled" (click)="click($event)"> submit </my-button>
应该是
<my-button [disabled]="isDisabled" (click)="click($event)"> submit </my-button>
您应该使用 [disabled]
属性 中提到的 documentation:
<button [disabled]="isDisabled" (click)="disableButton()">Disable button</button>
然后在你的代码中
export class AppComponent {
isDisabled = false;
disableButton() {
this.isDisabled = true;
// your code...
}
}
查看演示的 StackBlitz。
你可以在(click)
属性上查看:
<my-button [isDisabled]="isDisabled" (click)="!isDisabled && click($event)"> submit </my-button>
也是通过下面的CSS解决的:
# This prevents host to get a direct click
:host {
pointer-events: none;
}
# This prevents the span inside the button to "steal" the click from the button
:host /deep/ button span {
pointer-events: none;
}
# Now only the button can get a click
# Button is the only smart enough to stop propagation when needed
button {
pointer-events: auto;
}
现在你不需要像其他答案那样手动传递点击事件:你有旧的(点击)事件回来了:D
<my-button [isDisabled]="isDisabled" (click)="click($event)"> submit </my-button>
在你的自定义组件中,你只需要传递禁用的 属性:
<button [disabled]="isDisabled" #myButton>
<ng-content></ng-content>
</button>
同时考虑 stackblitz modified from .
首先,我们需要问问自己,为什么我们要创建一种新型的按钮组件,而我们已经有了一个原生按钮组件。它可能是这样的:
- 利用一些 Angular 助手,例如动画
- 在执行某些点击处理程序期间禁用按钮。
- 进度指示。
- ...
如果可以使用 本机按钮(解决方案 0)解决需求,请坚持使用。否则,继续。
在创建可重用文件之前我们需要了解两件重要的事情
按钮组件:
K1 只能禁用 HTML 元素的有限子集,
https://html.spec.whatwg.org/multipage/semantics-other.html#disabled-elements。这个
意味着即使元素被禁用也会触发点击处理程序。
K2 在Angular中,无法从内部控制外部事件
里面。 https://github.com/angular/angular/issues/12630
解决方案 1.点击处理程序作为输入
要解决 K2,您可以使用 @Input
回调而不是
事件绑定。然后你就可以从内部控制它,并且
您甚至可以访问内部回调的结果。它
看起来像:
<my-button [myClick]="doIt"> or with arguments <my-button [myClick]="doIt.bind(1)">
@HostListener('click') onClick(event) {
this.myClick();
}
因为你可以完全控制回调,你可以忽略调用
它是 disabled
。
一个需要这个解决方案的问题是一个带有进度指示的按钮。当您完全控制回调时,库按钮可以启动/停止进度条的动画,甚至可以通过在进行中禁用它来阻止额外的点击。将其与本模块中的进度按钮进行比较
https://github.com/michaeldoye/mat-progress-buttons 你需要的地方
为按钮的每个实例启动/停止动画!
缺点:外观不标准。你的图书馆用户会想这是为什么
回调输入而不是事件绑定...
解决方案二。CSS
您可以尝试使用 CSS pointer-events:none
解决 K1。它
会在表面上工作,阻止用户鼠标触发点击
事件。但是,您仍然可以实用地单击
按钮。当按钮为 'disabled'.
时,myButton.click()
仍会触发
缺点:'Disabled' 元素仍然 click
可用。可能,不适合
您的图书馆用户编写自动化测试。
解决方案3.组件化原生按钮
要使禁用和事件按预期工作,您需要应用
组件直接放在 HTML 按钮元素上。在 Angular Material 它看起来
喜欢 <button mat-button>
,
https://github.com/angular/components/blob/master/src/material/button/button.ts#L66
而且非常简单:
@Component({
selector: 'button[my-button]',
template: '<ng-content></ng-content>'
})
并使用它:
<button my-button (click)="doIt()" [disabled]="isDisabled">Save</button>
现在禁用 my-button
时不会触发点击事件。
缺点:原生按钮必须有,而且my-button
看起来更像
是指令而不是组件。
结论
我建议采用最符合要求的解决方案,而不是 CSS hack 解决方案。
如果您想在不使用输出的情况下保留旧版点击事件。
有一个基于前面的组合解决方案。
我的-button.component.html
<button [disabled]="disabled">
<ng-content></ng-content>
</button>
我的-button.component.ts
export class MyButtonComponent {
@HostBinding('style.pointer-events') get pEvents(): string {
if (this.disabled) {
return 'none';
}
return 'auto';
}
@Input()
disabled: boolean = false;
constructor() {}
}
您将在其中调用您的组件的父组件,例如app.component.html
<my-button [disabled]="isDisabled" (click)="onClickFnc()">
<span>Save which not trigger click when button is disabled</span>
</my-button>
我能够在 scss 中禁用禁用按钮的单击事件。这是我添加的
:host {
button {
&:disabled:active {
pointer-events: none;
}
}
}
这可以通过使用布尔变量来检查某些条件是否为真来实现,如下所示:
<my-button (click)="is_some_condition_true ? null : click($event)"> submit </my-button>
这个条件可以是例如:
将组件中的 editMode、addMode 或 isDisabled 等变量的初始值设置为 false,然后在按钮实际禁用时将其设置为 true。
参考:how-to-disabled-click-event-or-any-event-if-condition-is-false-true-in-angular
我正在创建一个像这样的可重用组件:
<my-button [isDisabled]="isDisabled" (click)="click($event)"> submit </my-button>
我想在 属性 isDisabled 为 true 时禁用点击事件,我尝试过类似的方法但它不起作用。
packages/component/my-button.component.html
<button [disabled]="isDisabled" #myButton>
<ng-content></ng-content>
</button>
packages/component/my-button.component.ts
@ViewChild('uxButton') uxButton: ElementRef;
@Input() isDisabled: boolean = false;
this.myButton.nativeElement.parentNode.removeEventListener('click' , (e) => {
e.stopPropagation();
});
我们可以addeventlistener/remove根据需要使用ElementRef/HostListener,但简单的修复方法如下。
click(event) {
if (this.isDisabled) {
return;
}
......
}
这样试试
<button [disabled]="isDisabled" (click)="btnClick.emit($event)">
<ng-content></ng-content>
</button>
@Input() isDisabled: boolean = false;
@Output() btnClick = new EventEmitter();
使用 Output
并且默认情况下,如果按钮被禁用,按钮单击事件将不起作用。好好利用它
<my-button [isDisabled]="isDisabled" (btnClick)="click($event)"> submit </my-button>
我认为问题出在您的代码中:
<my-button [isDisabled]="isDisabled" (click)="click($event)"> submit </my-button>
应该是
<my-button [disabled]="isDisabled" (click)="click($event)"> submit </my-button>
您应该使用 [disabled]
属性 中提到的 documentation:
<button [disabled]="isDisabled" (click)="disableButton()">Disable button</button>
然后在你的代码中
export class AppComponent {
isDisabled = false;
disableButton() {
this.isDisabled = true;
// your code...
}
}
查看演示的 StackBlitz。
你可以在(click)
属性上查看:
<my-button [isDisabled]="isDisabled" (click)="!isDisabled && click($event)"> submit </my-button>
也是通过下面的CSS解决的:
# This prevents host to get a direct click
:host {
pointer-events: none;
}
# This prevents the span inside the button to "steal" the click from the button
:host /deep/ button span {
pointer-events: none;
}
# Now only the button can get a click
# Button is the only smart enough to stop propagation when needed
button {
pointer-events: auto;
}
现在你不需要像其他答案那样手动传递点击事件:你有旧的(点击)事件回来了:D
<my-button [isDisabled]="isDisabled" (click)="click($event)"> submit </my-button>
在你的自定义组件中,你只需要传递禁用的 属性:
<button [disabled]="isDisabled" #myButton>
<ng-content></ng-content>
</button>
同时考虑 stackblitz modified from
首先,我们需要问问自己,为什么我们要创建一种新型的按钮组件,而我们已经有了一个原生按钮组件。它可能是这样的:
- 利用一些 Angular 助手,例如动画
- 在执行某些点击处理程序期间禁用按钮。
- 进度指示。
- ...
如果可以使用 本机按钮(解决方案 0)解决需求,请坚持使用。否则,继续。
在创建可重用文件之前我们需要了解两件重要的事情 按钮组件:
K1 只能禁用 HTML 元素的有限子集, https://html.spec.whatwg.org/multipage/semantics-other.html#disabled-elements。这个 意味着即使元素被禁用也会触发点击处理程序。
K2 在Angular中,无法从内部控制外部事件 里面。 https://github.com/angular/angular/issues/12630
解决方案 1.点击处理程序作为输入
要解决 K2,您可以使用 @Input
回调而不是
事件绑定。然后你就可以从内部控制它,并且
您甚至可以访问内部回调的结果。它
看起来像:
<my-button [myClick]="doIt"> or with arguments <my-button [myClick]="doIt.bind(1)">
@HostListener('click') onClick(event) {
this.myClick();
}
因为你可以完全控制回调,你可以忽略调用
它是 disabled
。
一个需要这个解决方案的问题是一个带有进度指示的按钮。当您完全控制回调时,库按钮可以启动/停止进度条的动画,甚至可以通过在进行中禁用它来阻止额外的点击。将其与本模块中的进度按钮进行比较 https://github.com/michaeldoye/mat-progress-buttons 你需要的地方 为按钮的每个实例启动/停止动画!
缺点:外观不标准。你的图书馆用户会想这是为什么 回调输入而不是事件绑定...
解决方案二。CSS
您可以尝试使用 CSS pointer-events:none
解决 K1。它
会在表面上工作,阻止用户鼠标触发点击
事件。但是,您仍然可以实用地单击
按钮。当按钮为 'disabled'.
myButton.click()
仍会触发
缺点:'Disabled' 元素仍然 click
可用。可能,不适合
您的图书馆用户编写自动化测试。
解决方案3.组件化原生按钮
要使禁用和事件按预期工作,您需要应用
组件直接放在 HTML 按钮元素上。在 Angular Material 它看起来
喜欢 <button mat-button>
,
https://github.com/angular/components/blob/master/src/material/button/button.ts#L66
而且非常简单:
@Component({
selector: 'button[my-button]',
template: '<ng-content></ng-content>'
})
并使用它:
<button my-button (click)="doIt()" [disabled]="isDisabled">Save</button>
现在禁用 my-button
时不会触发点击事件。
缺点:原生按钮必须有,而且my-button
看起来更像
是指令而不是组件。
结论
我建议采用最符合要求的解决方案,而不是 CSS hack 解决方案。
如果您想在不使用输出的情况下保留旧版点击事件。 有一个基于前面的组合解决方案。
我的-button.component.html
<button [disabled]="disabled">
<ng-content></ng-content>
</button>
我的-button.component.ts
export class MyButtonComponent {
@HostBinding('style.pointer-events') get pEvents(): string {
if (this.disabled) {
return 'none';
}
return 'auto';
}
@Input()
disabled: boolean = false;
constructor() {}
}
您将在其中调用您的组件的父组件,例如app.component.html
<my-button [disabled]="isDisabled" (click)="onClickFnc()">
<span>Save which not trigger click when button is disabled</span>
</my-button>
我能够在 scss 中禁用禁用按钮的单击事件。这是我添加的
:host {
button {
&:disabled:active {
pointer-events: none;
}
}
}
这可以通过使用布尔变量来检查某些条件是否为真来实现,如下所示:
<my-button (click)="is_some_condition_true ? null : click($event)"> submit </my-button>
这个条件可以是例如:
将组件中的 editMode、addMode 或 isDisabled 等变量的初始值设置为 false,然后在按钮实际禁用时将其设置为 true。
参考:how-to-disabled-click-event-or-any-event-if-condition-is-false-true-in-angular