【问题标题】:StencilJS Web Component: How to allow end-user to prevent default via custom click event?StencilJS Web 组件:如何允许最终用户通过自定义点击事件防止默认?
【发布时间】:2021-05-20 18:23:15
【问题描述】:

示例Stencil.js 网络组件:

import { Component, ComponentInterface, Event, EventEmitter, h, Host } from "@stencil/core";

@Component({
    tag: 'foo-testwebcomponent'
})
export class TestWebComponent implements ComponentInterface {
    @Event({
        eventName: 'foo-click',
        cancelable: true
    }) fooClick: EventEmitter;
    fooClickHandler() {
        this.fooClick.emit();
    }

    render() {
        return(
            <Host>
                <a href="#"
                   onClick={this.fooClickHandler.bind(this)}
                >Testing</a>
            </Host>
        )
    }
}

HTML:

<foo-testwebcomponent id="test"></foo-testwebcomponent>

<script>
  document.addEventListener('DOMContentLoaded', () => {
    document.getElementById('test')
            .addEventListener('foo-click', event => {
              event.preventDefault();
              console.log(`Foo Test Web Component clicked!`);
            });
  });
</script>

问题:

在 HTML 实现中,prevent 默认值不会阻止链接工作。

问题:

如何让我的 Web 组件的最终用户阻止默认设置并阻止链接工作?

我知道我可以在fooClickHandler() 中添加preventDefault()(见下文),但这对我来说似乎很奇怪。我想将控制权交给 Web 组件的最终用户。

@Event({
  eventName: 'foo-click',
  cancelable: true
}) fooClick: EventEmitter<MouseEvent>;
fooClickHandler(event: MouseEvent) {
  event.preventDefault();
  this.fooClick.emit();
}

【问题讨论】:

    标签: web-component stenciljs


    【解决方案1】:

    有两个独立的事件:

    1. 用户发起的点击事件
    2. 您的fooClick 自定义事件

    在您的示例中,您在自定义事件上调用 preventDefault(),但您需要在原始点击事件上调用它以防止链接导航。

    我知道有两种方法可以做到这一点:

    1:跟踪您的自定义活动是否被取消

    您可以使用defaultPrevented 属性检查用户是否在您的自定义事件中调用了preventDefault()fooClick 事件处理程序可以保持不变。

    fooClickHandler(clickEvent: MouseEvent) {
      const customEvent = this.fooClick.emit();
      if (customEvent.defaultPrevented) {
        clickEvent.preventDefault();
      }
    }
    

    查看this online demo

    2:传递点击事件

    将单击事件传递给fooClick 事件处理程序,以便用户可以取消它。

    fooClickHandler(clickEvent: MouseEvent) {
      this.fooClick.emit({ originalEvent: clickEvent });
    }
    

    在处理程序中:

    element.addEventListener('foo-click', event => {
      event.detail.originalEvent.preventDefault();
      console.log(`Foo Test Web Component clicked!`);
    });
    

    【讨论】:

    • 感谢您的帮助!我喜欢这两个例子。我实际上遇到了customEvent.defaultPrevented,但我不确定如何使用它来防止href 被触发。谢谢!
    【解决方案2】:

    一种方法是重载addEventListener 函数并捕获函数reference

    (需要更多的工作才能使其与嵌套元素一起使用,你会漂移)

    或者使用自定义方法addClick(name,func) 这样用户仍然可以添加任何监听器

    <script>
      customElements.define(
        "my-element",
        class extends HTMLElement {
          connectedCallback() {
            this.clicked = (evt)=>{
              document.body.append("component handler")
            }
            this.onclick = (evt) => {
                this.clicked(evt);
            }
          }
          addEventListener(name, func) {
            this.clicked = func;
          }
        }
      );
      document.addEventListener('DOMContentLoaded', () => {
        document.querySelector('my-element')
          .addEventListener('click', event => {
            document.body.append(`user handler`);
          });
      });
    </script>
    <my-element>Hello Web Components World!</my-element>

    您也可以使用旧的 onevent 处理程序:

    <script>
      customElements.define(
        "my-element",
        class extends HTMLElement {
          connectedCallback() {
            this.onclick = (evt) => console.log("component handler")
          }
        }
      );
      document.addEventListener('DOMContentLoaded', () => {
        let el = document.querySelector('my-element');
        el.onclick = event => console.log(`user handler`, el.onclick);
      });
    </script>
    <my-element onclick="console.log('inline')">Hello Web Components World!</my-element>

    【讨论】:

    • 感谢您的帮助,非常感谢! +1
    猜你喜欢
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多