首页 > 解决方案 > 如何以及在何处将“Esc”侦听器添加到 litElement 组件?

问题描述

我有使用 litElement 呈现的模态组件,我想通过 Escape 键使其可关闭,用于此模态组件的任何和所有实例。

我的问题是我在哪里以及如何做到这一点?在渲染中,在 firstUpdated? 您的帮助将不胜感激。

相关摘录:

    close() {
        this.hidden = true;
        this.dispatchEvent(new CustomEvent('modal-closed'));
    }

    _addKeyListener() {
        this.shadowRoot.addEventListener('keydown', function (event) {
            if (event.key === 'Escape') {
                this.close(); //presumably
            }
        });
    }

    render() {
        if (this.hidden) {
            return html``;
        }

        return html`
            <div id="background" class="${classMap({'u-is-hidden': this.hidden})}">
                <div class="modal">
                    <div id="modal-close" class="${classMap({'u-is-hidden': !this.closeable})}">
                        <img src="img/close-icon.svg" @click="${this.close.bind(this)}" alt="close">
                    </div>
                    <div id="modal-header">
                        <slot name="header"></slot>
                    </div>
                    <div id="modal-body">
                        <slot name="body"></slot>
                    </div>
                    <div id="modal-footer">
                        <slot name="footer"></slot>
                    </div>
                </div>
            </div>
        `;
    }

标签: javascripthtmllit-element

解决方案


我在模态组件中将更新的生命周期函数用于相同的目的:

import { html, LitElement } from "lit";
import { customElement, property, query } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { elementStyles } from "./modal.element.styles";

@customElement('very-custom-modal')
export class ModalElement extends LitElement {
  
  static styles = [elementStyles];
  
  @property({ type: Boolean })
  open = false;

  private _handlerClose() {
    this.dispatchEvent(new CustomEvent("close"));
  }

  private _keydownHandler(e: Event) {
    if ((e as KeyboardEvent).code === 'Escape') {
      this._handlerClose();
    }
  }

  updated() {
    if (this.open) {
      this.getRootNode().addEventListener('keydown', (e: Event) => this._keydownHandler(e));
    } else {
      this.getRootNode().removeEventListener('keydown', (e: Event) => this._keydownHandler(e));
    }
  }
  
  render() {
    const classes = { 'modal': true, 'open': this.open, 'hidden': !this.open };
    return html`
      <div  class=${classMap(classes)}>
        <div class="modal-content">
          <span class="close" @click=${this._handlerClose}>&times;</span>
          <p class="text">Some text in the Modal..</p>
        </div>
      </div>  
    `;
  }
}

和款式:

import { css } from "lit";

export const elementStyles = css`
  .modal {
    position: fixed;
    width: 100vw;
    height: 100vh;
    background-color: rgba(0, 0, 0, 0.8);
    top: 0;
    left: 0;
    z-index: 99;
  }
  .modal-content {
    position: absolute;
    top: calc((100vh - 300px) / 2);
    left: calc((100vw - 500px) / 2);
    background-color: #fefefe;
    margin: auto;
    padding: 20px;
    border: 1px solid #888;
    width: 50%;
    top: 30%;
  }
  .close {
    color: #aaaaaa;
    float: right;
    font-size: 28px;
    font-weight: bold;
  }
  .close:hover,
  .close:focus {
    color: #000;
    text-decoration: none;
    cursor: pointer;
  }
  .open {
    display: block;
  }
  .hidden {
    display: none;
  }
`;

该组件根据状态属性“打开”的依赖性更改其行为。默认情况下它是假的,所以组件有'.hidden'类。更改 'open' 属性后,组件会根据 Lit 文档 ( https://lit.dev/docs/components/lifecycle/#reactive-update-cycle ) 进行更新,并使用 '.open' 类进行更新,以防属性为'真的'。我使用 'updated' 事件来添加/删除 keydown 监听器。作为一个小结论,该组件仅在它处于活动状态(显示)时才挂钩 keydown 事件,否则我们不需要此处理程序,因此如果控制属性为“假”,则可以将其删除。由于属性应该设置在组件之外,我们需要向父组件发出“关闭”事件以将属性更改为“假”。


推荐阅读