0

我创建了自己的自定义按钮,如下所示


@Component({
    tag: "idv-button",
    styleUrl: "idv-button.scss",
    shadow: true,
})
export class IdvButton {
    @Prop({ reflect: true }) text: string;
    @Prop({ reflect: true }) disabled: boolean = false;

    render(): any {
        return (
            <button disabled={this.disabled} onClick={this.onClick}>
                <span class="btn-text">{this.text}</span>
            </button>
        );
    }

    private onClick(event: Event): void {
        if (this.disabled) {
            console.log("prevent default", event); // it doesn't come here at all
            event.preventDefault();
        }
    }

}

并在 stenciljs 的另一个组件中像这样使用它

                        <idv-button
                            text="my button"
                            disabled={true}
                            onClick={this.startClick.bind(this)}>
                        </idv-button>

问题是虽然按钮是disabled,即使我试图阻止默认,onClick 仍然发生并被this.startClick调用

我该如何解决这个问题?

4

3 回答 3

1

我认为属性如何on...与自定义元素一起使用存在一些混淆。在 Stencil 组件上,如果一个属性以 开头on,那么它将成为与该属性的其余部分同名的事件处理程序(大小写会自动转换)。例如。如果您的组件发出一个名为myEvent(使用 Stencil 的@Event装饰器和EventEmitter类型)的事件,那么您可以使用onMyEvent属性为您的组件添加该事件的侦听器。此处的文档中的示例对此进行了解释。

在您的情况下,您正在向onClick您的组件添加一个属性,该属性处理该click元素的事件,这是一个不需要设置的本机 DOM 事件,即任何 HTML 或自定义元素都会触发一个click事件点击(不仅仅是按钮)。

所以即使你的组件就像

@Component({ tag: "idv-button" })
export class IdvButton {
    render() {
        return <p>Hello, World!</p>;
    }
}

你用它就像

<idv-button onClick={console.log} />

click每次单击文本时,您仍然会收到该事件。


我认为您要实现的是将onClick处理程序传递给底层按钮。最简单的方法是将处理函数作为道具传递。

import { Component, h, Host, Prop } from '@stencil/core';

@Component({ tag: "idv-button", shadow: true })
export class IdvButton {
    @Prop() disabled?: boolean;
    @Prop() clickHandler: (e: MouseEvent) => void;

    render() {
        return (
            <button disabled={this.disabled} onClick={this.clickHandler.bind(this)}>
                <slot />
            </button>
        );
    }
}
<idv-button clickHandler={console.log}>
    My Button
</idv-button>

不确定您是否真的需要 bind this,并将其更改为将内容作为插槽传递,但可以随意放弃该建议。

顺便说一句,调用 prop 非常诱人,onClick但这会与本on...机事件的事件处理发生冲突click,因此 Stencil 会在编译时警告您。


另一种解决方案是在设置道具pointer-events: none时添加到主机。disabled这就是 Ionicion-button所做的(参见button.tsx#L220button.scss#L70-L74)。

在你的情况下,它会像

import { Component, Host, h, Prop } from '@stencil/core';

@Component({ tag: "idv-button", shadow: true })
export class IdvButton {
    @Prop() disabled?: boolean;

    render() {
        return (
            <Host style={{ pointerEvents: this.disabled ? 'none' : undefined }}>
                <button disabled={this.disabled}>
                    <span class="btn-text">
                        <slot />
                    </span>
                </button>
            </Host>
        );
    }
}

(该onClick属性将自动在您的组件上运行,因为它是默认事件)

于 2020-12-30T13:32:33.167 回答
1
于 2021-06-01T08:08:30.807 回答
0

我参加聚会迟到了,但是,使用{...(this.disabled || null)}代替disabled={this.disabled}呢?

于 2021-09-17T18:48:17.313 回答