简体   繁体   English

点亮元素事件侦听器不会强制重新渲染

[英]lit element event listener doesn't force re render

I have the following code:我有以下代码:

  @property({type: Number}) ScreenSizeEnum = ScreenSize.Desktop;

  @property({type: Array}) menuData: IMenu[] = [];
  @property({type: Boolean}) isMobileMenuOpen: boolean = false;


  constructor() {
    super();
  }

  connectedCallback() {
    super.connectedCallback();
    window.addEventListener('resize', this.onResizeEvent);
  }

  disconnectedCallback() {
    window.removeEventListener('resize', this.onResizeEvent);
    super.disconnectedCallback();
  }

  onResizeEvent() {
    let oldVal = this.ScreenSizeEnum;
    if (window.outerWidth > 1000) {
      this.ScreenSizeEnum = ScreenSize.Desktop;
    } else if (window.outerWidth > 700 && window.outerWidth < 1000) {
      //Tablet
      this.ScreenSizeEnum = ScreenSize.Tablet;
    } else if (window.outerWidth < 700) {
      // mobile
      this.ScreenSizeEnum = ScreenSize.Mobile;
    }
    
  }


  render() {
    let device = this.getDeviceType();

    if (device == "desktop" || this.ScreenSizeEnum == ScreenSize.Desktop) {
      return html`
      <nav class="animate__animated animate__bounce animate__slow">
        <ul class="menu-ul">
       ${this.menuData.map(
        menuItem => html`
           <universe-menu-main .linkText="${menuItem.linkText}" .link="${menuItem.link}" .subMenu="${menuItem.subMenu}"></universe-menu-main>
          `
      )}
        </ul>
     </nav>

    `
    } else if (device == 'tablet' || this.ScreenSizeEnum == ScreenSize.Tablet) {
      return html`
        <tablet-menu .menuData="${this.menuData}"></tablet-menu>
    `;
    } else if (device == 'mobile' || this.ScreenSizeEnum == ScreenSize.Mobile) {
      return html`
      <mobile-menu .menuData="${this.menuData}" .isOpen="${this.isMobileMenuOpen}"></mobile-menu>
    `;
    }


  }

  getDeviceType() {
    const ua = navigator.userAgent;
    if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {
      return "tablet";
    }
    if (
      /Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(
        ua
      )
    ) {
      return "mobile";
    }
    return "desktop";
  };

The resize event is fired, however whenever it changes the ScreenSizeEnum , the render function does not run.触发 resize 事件,但是每当它更改ScreenSizeEnumrender函数都不会运行。

Why does this happen, and how might I fix this?为什么会发生这种情况,我该如何解决?

Your problem is on how you have subscribed to the events and the funky behaviour of this in JS:您的问题在于您如何订阅事件以及在 JS 中的this时髦行为:

window.addEventListener('resize', this.onResizeEvent);

This means that inside onResizeEvent() the term this will refer to the window being resized, not your component.这意味着在onResizeEvent() ,术语this将指正在调整大小的窗口,而不是您的组件。

You can fix this by using a lambda to force the this context (as inside the => body this is always the current context, not the event's:您可以通过使用 lambda 强制this上下文来解决此问题(在=>正文中, this始终是当前上下文,而不是事件的:

window.addEventListener('resize', () => this.onResizeEvent());

Now, when onResizeEvent() event fires, inside it this will refer to the control, not the window.现在,当onResizeEvent()事件触发时,在它里面this将引用控件,而不是窗口。

The problem is that now you can't unsubscribe.问题是现在你不能退订。 We need to keep a reference to the wrapped method to remove it:我们需要保留对包装方法的引用以将其删除:

connectedCallback() {
    super.connectedCallback();
    window.addEventListener('resize', this.resizeContext, { capture: false, passive: true });
}

disconnectedCallback() {
    window.removeEventListener('resize', this.resizeContext);
    super.disconnectedCallback();
}

private readonly resizeContext: () => void = () => this.onResizeEvent();

As this is an external event causing an update it's a better fit for a ReactiveController to fire an update on the window events, and isolate all this resize code from your component.由于这是一个导致更新的外部事件,因此更适合ReactiveController触发窗口事件的更新,并将所有这些调整大小的代码与您的组件隔离。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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