首页 > 解决方案 > 如何在 Web 组件中捕获自定义事件?

问题描述

为了让 Web 组件相互通信,我使用了自定义事件。让我们想象一下:

WebComponentA 使用或包含 WebComponentB,如果单击按钮,WebComponentB 会发送一个 CustomEvent(气泡:true,composition:true)。如果 WebComponentB 发送此事件,WebComponentA 想要做某事。

我应该如何在 WebComponentB 中调度事件?

window.dispatchEvent(customEvent);

或者

this.shadowRoot.dispatchEvent(customEvent);

我应该如何在 WebComponentA 中捕获事件?

window.addEventListener(custom-event, () => {
);

或者

this.shadowRoot.addEventListener(custom-event, () => {
);

我应该考虑使用一种或另一种的负面影响吗?

谢谢!

标签: javascriptdomweb-componentcustom-eventsnative-web-component

解决方案


在组件本身上调度事件,bubble: true, composed: true这样事件就会冒泡到任何关注它的东西。当您想要非常明确地拥有大量可预测性和共享状态时,我的意思是这确实是一种紧密耦合,那么只需在全局上编排事件self(即window在浏览器中)。这里有一些随机的例子,我希望有所帮助,他们所做的只是为了展示一个例子而相对无用。整体的想法是在有意义的情况下松散耦合事物,事件只是传递与状态变化相关的消息。组件总是可以相当隔离,并且无论它在什么上下文中运行,都可以单独关注它对该信息的作用(准备和接收模型——这是功能模式高度适用的地方)。如果需要更多细节或感到困惑,请随时将其拼写出来,我们可以尝试提供帮助。

还要注意,因为我没有设置任何 shadowRoot,所以组合标志在此示例中根本没有用。

宽广地:

  • 全局:(其他上下文中的self同义词window或工作人员);此处的协调事件旨在与许多事物紧密耦合——当需要非常具体的协调系统时,这是迄今为止最简单的组织方案;对于这种情况,只需在此处侦听和调度事件;在 and 中添加和删除事件侦听connectedCallbackdisconnectedCallbackself.dispatchEvent('type', {detail:...})然后不再需要在任何地方发送冒泡或直接冒泡等。

  • 节点:在树的任何级别,当组件具有任何状态或任何类型的事件时,处理场景并创建一个适当的消息作为event.detail和一个合理的名称作为event.type,然后从处理该逻辑的节点调度它。其他节点——在自己的父节点等上——可以监视event.bubble,当从影子节点调度时,这些事件可以使用composed:true标志来允许在 shadowRoot 之外继续事件。或者该元素可以处理内部事件并分派适合该类型的新型事件和有效负载。

      <my-global>my global </my-global>
      <my-aye> aye (parent)
          <my-bee> bee (child) </my-bee>
      </my-aye>
      <my-bee> bee </my-bee>
    
    
      function eventdetails(event){
          const {type, detail} = event;
          console.log({type, detail, self:this, path: event.composedPath(), event});
      }
    
      customElements.define('my-global', class MyGlobalWatch extends HTMLElement{
          constructor(){
              super();
              this.global = this.global.bind(this);
          }
          global(event){
              eventdetails.call(this, event);
          }
          connectedCallback(){
              self.addEventListener('global', this.global);
          }
          disconnectedCallback(){
              self.removeEventListener('global', this.global);
          }
      });
      customElements.define('my-aye', class MyAye extends HTMLElement{
          constructor(){
              super();
              this.addEventListener('hi-aye', this.handle);
              this.addEventListener('hi-bee', this.handle);
          }
          handle(event){
              eventdetails.call(this, event);
              if(event.type === 'hi-bee'){
                  self.dispatchEvent(new CustomEvent('global', {detail: event.detail, cancelable: true, composed: true, bubbles: false}));
              }
          }
      });
      customElements.define('my-bee', class MyBee extends HTMLElement{
          constructor(){
              super();
              this.addEventListener('hi-aye', this.handle);
              this.addEventListener('hi-bee', this.handle);
              this.ticker = this.ticker.bind(this);
          }
          handle(event){
              eventdetails.call(this, event);
          }
          ticker(){
              // 3 events of the same type, different configuration
              this.dispatchEvent(new CustomEvent('hi-aye', {detail: {payload:'> -composed +bubbles'}, cancelable: true, composed: false, bubbles: true}));
              this.dispatchEvent(new CustomEvent('hi-aye', {detail: {payload:'> +composed +bubbles'}, cancelable: true, composed: true, bubbles: true}));
              this.dispatchEvent(new CustomEvent('hi-aye', {detail: {payload:'> -composed -bubbles'}, cancelable: true, composed: false, bubbles: false}));
    
              this.dispatchEvent(new CustomEvent('hi-bee', {detail: {stuff:'things'}, cancelable: true, composed: true, bubbles: true}));
    
              this._timer = setTimeout(this.ticker, 1234);
          }
          connectedCallback(){
              this.ticker();
          }
          disconnectedCallback(){
              clearTimeout(this._timer);
          }
      });
    

推荐阅读