Lit-element - :host 选择器不会在 Safari 上触发渲染

Lit-element - :host selector is not triggering render on Safari

在我正在处理的一个项目中,我有这个 LitElement 组件,它是 绝对定位 并确定它的 left 或 top 根据其反应特性定位。

我只在 Safari 中遇到过问题,包括 iOS Safari/Chrome/Firefox。该元素已更新其阴影样式,但在视图中它根本没有移动。当我发现 当光标悬停元素 或退出浏览器视图时,元素弹出到预期位置时,我意识到这是一个渲染问题。

我设法用更简单的代码重现了这个问题:

我的-elem.ts:

import { LitElement, html, property, customElement, css } from 'lit-element';

@customElement('my-elem')
export class MyElem extends LitElement {
    @property({ type: Number, reflect: true })
    left: number = 30

    static get styles() {
        return css`
            :host { position: absolute; }
            div { position: absolute; }
        `;
    }

    render() {
        return html`
            <style>
                :host { left: ${this.left}px; }
            </style>
            <div> Hello </div>
        `;
    }
}

index.html:

<html lang="en">
<head>
  <script src="my-elem.ts"></script>
</head>
<body>
    <my-elem id="my-elem" left="50"></my-elem>
    <button id="move-btn">move</button>
    <script>
        const elem = document.getElementById('ma-elem');
        const moveBtn = document.getElementById('move-btn');
        moveBtn.onclick = function() {
            elem.left += 30;
        }
    </script>
</body>
</html>

我发现这只发生在 :host 选择器上。如果阴影样式更新 divleft,它可以毫无问题地呈现。

由于性能问题,我希望避免强制浏览器 layout/paint。

我认为您问题的根源在于您正试图在呈现模板中的样式元素内使用表达式。

LitElement 指南提到以这种方式使用它们 has limitations and can cause performance issues。我认为您的问题只是其中之一,因此您应该删除该样式元素。

作为替代方案,由于您想要影响宿主元素,如果您不使用 属性 而是直接设置宿主元素的样式,实际上可以通过更简单的方式执行此操作。

所以当使用 my-elem 时,代码看起来像:

<my-elem style="left: 30px;"></my-elem>

这是因为在阴影 DOM 中应用于 :host 的样式的优先级低于使用 类 或其父项的样式属性应用于它的样式。

或者,如果你真的想保留 属性,你可以 create property accessors 代替 left 属性,然后像这样从那里设置主机的样式:

export class MyElem extends LitElement {
  // other code
  
  set left(value) {
    const oldValue = this.left;
    this._left = value;
    this.style.setProperty('left', `${value}px`)
    this.requestUpdate('left', oldValue);
  }
  
  get left() {
    return this._left;
  }
  
}