单击时切换所有 stencil.js 个同类组件

Toggle all stencil.js components of the same kind when clicked

我正在创建一个工具栏,将用于文本编辑。

工具栏中的每个项目都是使用以下代码创建的:

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

@Component({
  tag: 'spa-toolbar-item',
  styleUrl: 'spa-toolbar-item.scss',
})

export class spaToolbarItem {
  @Prop({reflectToAttr: true, mutable: true}) toggle: boolean = false;
  @Prop({reflectToAttr: true}) type: string;
  @Event() onToggle: EventEmitter;

  toggleComponent(): void {
    this.toggle = !this.toggle;
    this.onToggle.emit({visible: this.toggle});
  }

  render() {
    return [
      <button onClick={() => this.toggleComponent()}>
        <slot/>
      </button>,
      <div class={this.toggle ? 'is-active' : null}>
        {this.type == 'font'
          ? <div class={this.type}>
            <span class="arial">Arial</span>
            <span class="georgia">Georgia</span>
            <span class="palatino">Palatino</span>
            <span class="tahoma">Tahoma</span>
            <span class="times">Times New Roman</span>
            <span class="helvetica">Helvetica</span>
            <span class="courier">Courier New</span>
            <span class="lucida">Lucida Sans Typewriter</span>
            <span class="verdana">Verdana</span>
          </div>
          : null}
      </div>
    ]
  }
}

这按预期工作,但是,我希望所有其他下拉菜单在单击一个项目时关闭,因此基本上 'this.toggle' 需要应用于所有非活动下拉菜单。我该怎么做?

你可以用 pure javascript 做的是,遍历所有元素 class is-active,并将每个元素的 toggle 属性设置为 0(或其他任何方式)你在做)

示例:

new Array(document.getElementsByClassName('is-active')).forEach(function(e){/*Set toggle property to 0*/});

这个做的是,搜索所有带[=11=的元素],遍历它们,并设置一个函数,在这个函数中参数e等于当前元素,你可以设置你的属性那里。

因此,我们的想法是将 addEventListener 应用于您的文档以及组件本身(主机 - 下拉列表)。为此,您可以使用像 componentdidload.

这样的生命周期钩子
import {Component, h, Prop, Event, EventEmitter} from '@stencil/core';

@Component({
  tag: 'spa-toolbar-item',
  styleUrl: 'spa-toolbar-item.scss',
})

export class spaToolbarItem {
  @Prop({reflectToAttr: true, mutable: true}) toggle: boolean = false;
  @Prop({reflectToAttr: true}) type: string;
  @Event() onToggle: EventEmitter;

private hostElement;
private buttonElement;
  closeDropdown(){
    this.toggle = false;
  }
  toggleComponent(): void {
    this.toggle = !this.toggle;
    this.onToggle.emit({visible: this.toggle});
  }

render() {
 return 
 <Host ref={(el) => this.hostElement = el}>
   //everything you had before in the return value
 </Host>
}

 componentDidLoad(){
  document.addEventListener("click", ()=>{this.clickManager("document");}, true)
  this.hostElement.addEventListener("click", ()=>{this.clickManager("dropdown");}, true)
 }

 private clickManager(identifier){
   if(identifier == "dropdown"){
     //the clicked dropdown -> active dropdown
     this.toggleComponent();
     return;
   }
   //all non active Dropdowns
   this.closeDropdown();
 }

}

如您所见,我们有两个调用 clickManager 的事件。第一个是文档,第二个是您单击的下拉菜单。当然,您必须删除按钮上的 onclick 事件,但此代码无法按预期工作。现在您可以决定如果单击下拉菜单会发生什么,以及所有非活动下拉菜单会发生什么。

这是基本概念,如有需要,请随意调整和更改。

谢谢 Christian,我最终在下面使用了这个解决方案。

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

@Component({
  tag: 'spa-toolbar-item',
  styleUrl: 'spa-toolbar-item.scss',
})

export class spaToolbarItem {
  @Prop({reflectToAttr: true, mutable: true}) isOpen: string = 'false';
  @Prop({reflectToAttr: true}) type: string;
  @Element() el: HTMLElement;

  openDropdown() {
    function closeDropdown() {
      let dropdowns = document.querySelectorAll('spa-toolbar-item[is-open]');
      dropdowns.forEach(item => {
        item.setAttribute('is-open', 'false')
      });
    }

    if (this.el.getAttribute('is-open') == 'true') {
      closeDropdown();
      return
    }

    if (this.el.getAttribute('is-open') == 'false') {
      closeDropdown();
      this.el.setAttribute('is-open', 'true')
    }
  }

  render() {
    return (
      <Host>
        <button onClick={this.openDropdown.bind(this)}>
          <slot/>
        </button>
        <div class={this.type}>
          {this.type == 'font'
            ? <div>
              <span class="arial">Arial</span>
              <span class="georgia">Georgia</span>
              <span class="palatino">Palatino</span>
              <span class="tahoma">Tahoma</span>
              <span class="times">Times New Roman</span>
              <span class="helvetica">Helvetica</span>
              <span class="courier">Courier New</span>
              <span class="lucida">Lucida Sans Typewriter</span>
              <span class="verdana">Verdana</span>
            </div>
            : null}
        </div>
      </Host>
    )
  }
}