Как передать событие ребенку в LitElement - PullRequest
2 голосов
/ 15 января 2020

Я хочу создать раскрывающееся меню, чтобы при нажатии на вход отображалось меню с переключателем, который удаляет или помещает «скрытый» класс

У меня есть этот метод

toggleMenu() {
    this.classList.toggle("hidden");
}

А вот и шаблон.

render(){
   return html`
       <input @click="${this.toggleMenu}" type="button">
       <ul class="hidden">
           <slot></slot>
       </ul>
   `;
}

Ответы [ 2 ]

4 голосов
/ 16 января 2020

Одно простое решение - добавить свойство к вашему пользовательскому элементу, например open, которое переключается в вашем методе toggleMenu:

static get properties() {
  return {
    open: { type: Boolean },
  };
}

constructor() {
  super();
  this.open = false;
}

toggleMenu() {
  this.open = !this.open;
}

Затем в вашем методе render установите <ul> атрибут class, основанный на значении this.open:

render(){
  return html`
    <button @click=${this.toggleMenu} type="button">Toggle</button>
    <ul class=${this.open ? '' : 'hidden'}>
      <slot></slot>
    </ul>
  `;
}

Это можно увидеть в следующем фрагменте кода:

// import { LitElement, css, html } from 'lit-element';
const { LitElement, css, html } = litElement;

class DropDownMenu extends LitElement {
  static get properties() {
    return {
      open: { type: Boolean },
    };
  }

  static get styles() {
    return css`
      ul.hidden {
        display: none;
      }
    `;
  }

  constructor() {
    super();
    this.open = false;
  }
  
  toggleMenu() {
    this.open = !this.open;
  }

  render(){
    return html`
      <button @click=${this.toggleMenu} type="button">Toggle</button>
      <ul class=${this.open ? '' : 'hidden'}>
        <slot></slot>
      </ul>
    `;
  }
}
customElements.define('drop-down-menu', DropDownMenu);
<script src="https://bundle.run/lit-element@2.2.1"></script>

<drop-down-menu>
  <li>Item 1</li>
  <li>Item 2</li>
</drop-down-menu>

Если вы хотите применить дополнительные классы к <ul>, вы захотите изучить функцию classMap, как описано в LitElement docs .


В качестве альтернативы, вы можете добавить reflect: true к объявлению свойства open, которое позволяет показать или скрыть <ul>, используя только CSS, вместо установки его class in render:

static get properties() {
  return {
    open: {
      type: Boolean,
      reflect: true,
    },
  };
}

static get styles() {
  return css`
    ul {
      display: none;
    }
    :host([open]) ul {
      display: block;
    }
  `;
}

Вот оно в рабочем фрагменте:

// import { LitElement, css, html } from 'lit-element';
const { LitElement, css, html } = litElement;

class DropDownMenu extends LitElement {
  static get properties() {
    return {
      open: {
        type: Boolean,
        reflect: true,
      },
    };
  }

  static get styles() {
    return css`
      ul {
        display: none;
      }
      :host([open]) ul {
        display: block;
      }
    `;
  }

  constructor() {
    super();
    this.open = false;
  }
  
  toggleMenu() {
    this.open = !this.open;
  }

  render(){
    return html`
      <button @click=${this.toggleMenu} type="button">Toggle</button>
      <ul>
        <slot></slot>
      </ul>
    `;
  }
}
customElements.define('drop-down-menu', DropDownMenu);
<script src="https://bundle.run/lit-element@2.2.1"></script>

<drop-down-menu>
  <li>Item 1</li>
  <li>Item 2</li>
</drop-down-menu>

Оба эти подхода являются общими, и лучший вариант для вашего приложения будет зависеть от вашего варианта использования и личных предпочтений.

1 голос
/ 19 января 2020

Мне бы хотелось, чтобы все было просто: если вам нужна ссылка на узел DOM, передайте событие в функцию, как показано ниже:

toggleMenu(ev) {
    ev.target.classList.toggle("hidden");
}

И для метода рендеринга

render(){
   return html`
       <input @click="${(ev)=>{this.toggleMenu(ev)}}" type="button">
       <ul class="hidden">
           <slot></slot>
       </ul>
   `;
}

И все готово

...