Веб-компонент StencilJS: Как разрешить конечному пользователю предотвращать использование по умолчанию с помощью пользовательского события щелчка?

#web-component #stenciljs

Вопрос:

Пример 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 параметр запретить по умолчанию не останавливает работу ссылки.

Вопрос:

Как я могу разрешить конечному пользователю моего веб-компонента запретить использование по умолчанию и запретить работу ссылки?

Я знаю, что могу добавить preventDefault() fooClickHandler() (см. Ниже), но мне это кажется странным. Я хотел бы передать управление конечному пользователю веб-компонента.

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

Ответ №1:

Есть два отдельных события:

  1. Событие щелчка, инициированное пользователем
  2. Ваше fooClick пользовательское мероприятие

В вашем примере вы вызываете preventDefault() пользовательское событие, но вам нужно вызвать его в исходном событии щелчка, чтобы предотвратить переход по ссылке.

Я знаю два способа добиться этого:

1. Отследите, отменено ли ваше пользовательское событие

Вы можете проверить, вызывал ли пользователь preventDefault() ваше пользовательское событие, используя это defaultPrevented свойство. Обработчик fooClick событий может оставаться прежним.

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

Ознакомьтесь с этой онлайн-демонстрацией.

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!`);
});
 

Комментарии:

1. Спасибо вам за вашу помощь! Мне нравятся оба примера. Я действительно наткнулся customEvent.defaultPrevented , но я не был уверен, как это использовать, чтобы href предотвратить стрельбу. Спасибо!

Ответ №2:

Одним из способов было бы перегрузить addEventListener функцию и захватить ссылку на функцию

(нужно еще немного поработать, чтобы заставить его работать с вложенными элементами, вы получите дрейф)

Или используйте пользовательский метод 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. Спасибо вам за вашу помощь, я действительно ценю это! 1