【问题标题】:Toggle all stencil.js components of the same kind when clicked单击时切换所有相同类型的 stencil.js 组件
【发布时间】:2020-03-04 09:38:19
【问题描述】:

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

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

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”应用于所有非活动下拉菜单。我该怎么做?

【问题讨论】:

    标签: javascript typescript stenciljs tsx


    【解决方案1】:

    你可以用纯 javascript 做的是,遍历所有元素与类是活动的,并将每个元素的切换属性设置为 0(或任何你正在做的方式)

    示例:

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

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

    【讨论】:

    • 但是如何访问循环内的切换属性?
    【解决方案2】:

    所以我们的想法是在您的文档以及组件本身(主机 - 下拉菜单)上应用 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 事件,但此代码无法按预期工作。现在您可以决定如果单击下拉菜单会发生什么,以及所有非活动下拉菜单会发生什么。

    这是基本概念,如果需要,您可以随意调整和更改。

    【讨论】:

      【解决方案3】:

      感谢 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>
          )
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-19
        • 1970-01-01
        • 2022-08-14
        相关资源
        最近更新 更多