简体   繁体   中英

How to pass event to a child in LitElement

I want to make a drop-down menu and that when clicking on the input, the menu is displayed with a toggle that removes or places the 'hidden' class

I have this method

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

And here the template.

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

One straightforward solution is to add a property to your custom element, eg open , that is toggled in your toggleMenu method:

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

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

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

Then in your render method set the <ul> 's class attribute based on the value of this.open :

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

You can see this working in the below snippet:

 // 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>

If you want to apply additional classes to the <ul> you'll want to look into the classMap function as described in the LitElement docs .


Alternatively, you can add reflect: true to the open property declaration, which lets you show or hide the <ul> using CSS alone, rather than setting its 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;
    }
  `;
}

Here it is in a working snippet:

 // 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>

Both of these are common approaches and the best one for your application will depend on your use case and personal preferences.

I like to keep it simple, if you need a reference to the DOM node then pass the event to the function like the following:

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

And for the render method

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

And you're done

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM