如何使用 LitElement 观察 属性 变化

How to observe property changes with LitElement

我不知道如何观察 LitElement 中的 属性 变化。

我一直在尝试这些方法,但我无法使它们起作用:

  static get properties() {
    return {
      temp1:String,
      temp2: {
       type:String,
       observer: '_temp2Changed'
        }
  };

  temp1Changed(newValue, oldValue){
    console.log("temp1 changed")
  }
  _temp2Changed(newValue, oldValue){
    console.log("temp2 changed")
  }

我从 Polymer 的 PWA 入门套件中找到了解决方案。

将以下内容添加到您的元素定义中:

_propertiesChanged(props, changed, oldProps) {
    console.log("_propertiesChanged(props, changed, oldProps):");
    console.log(props);    
    console.log(changed);  
    console.log(oldProps); 
    if (changed && 'temp1' in changed) {
      console.log("if temp1:"+changed.temp1);
    }
    super._propertiesChanged(props, changed, oldProps); //This is needed here
}

console output:
_propertiesChanged(props, changed, oldProps):
{temp1: "newVal1", temp2: "val2"}
{temp1: "newVal1"}
{temp1: "val1"}
if temp1:newVal1

LitElement 会在每次 属性 更改时自动重新渲染,只要 属性 已在您的“_render”方法中定义。

LitElement 中注明了这一点 readme

React to changes: LitElement reacts to changes in properties and attributes by asynchronously rendering, ensuring changes are batched. This reduces overhead and maintains consistent state.

例如:

_render({firstName, lastName}) {
  return html`
    <div> Hello ${firstName} ${lastName} </div>
  `
};

每次您的 firstName 和 lastName 属性更改时都会重新呈现。我希望这能提供一点清晰度。

版本 0.6.0+

首先,您必须指定元素属性。 您可以通过创建一个静态 getter 来实现,其中 return 是一个对象,包括它们的名称作为键和它们的属性相关配置。

当更改的属性导致重新渲染时,将调用 updated 生命周期方法。第一个参数将 return 更新前的值。

class MyComponent extends LitElement {
  static get properties() {
    return {
      foo: {}
    };
  }

  constructor() {
    super();
    this.foo = 0;
    setInterval(() => this.foo++, 1000);
  }

  updated(changedProperties) {
    console.log(changedProperties); // logs previous values
    console.log(this.foo); // logs current value
  }

  render() {
    return html`${this.foo}`;
  }
}

customElements.define("my-component", MyComponent);

我个人重写了 "requestUpdate" 方法以在渲染前了解变化。

我的用例是拦截 "label" 属性的变化以触发异步数据请求。

下面的代码段(在 TypeScript 中):

@customElement('my-element')
export default class MyElement extends LitElement {

    @property({type: String})
    label: string | null = null;

    @property({attribute: false})
    private isLoading: boolean = false;

    @property({attribute: false, noAccessor: true})
    private data: MyData | null = null;

    protected render() {/*some code*/}

    requestUpdate(name?: PropertyKey, oldValue?: unknown) {
        if(name && name == "label" && this.label !== oldValue) {
            this.isLoading = true;
            requestData(this.label, this._callbackData);
        }
        return super.requestUpdate(name, oldValue);
    }

    private _callbackData(data: MyData}) {
        this.data = data;
        this.isLoading = false;
    }

}

这样一来,我的元素只渲染了两次:一次带有新标签并加载为 true,然后在数据可用时渲染另一次。

属性'hasChanged'选项:

您可以在静态属性 getter 内的 属性 声明中定义此 'hasChanged' 选项。就像您使用 'type' 选项一样。

hasChanged 应该 return true 来更新元素。

myProp: { hasChanged(newVal, oldVal) {
 // compare newVal and oldVal
 // return `true` if an update should proceed
}}

检查一下here

生命周期方法:已更新

有一个名为 'updated' 的生命周期方法会在每次 属性 更改时触发。

此方法接收 'changedProperties' 及其之前的值作为参数,因此您可以将它们与当前值进行比较,然后决定要用它做什么。

查看 'updated' 文档 here

实施 shouldUpdate() 方法。 Source here.

Controls whether an update should proceed. Implement shouldUpdate to specify which property changes should cause updates. By default, this method always returns true.

function shouldUpdate(changedProperties: Map<any, any>) {
    changedProperties.forEach((oldValue, propName) => {
        const newValue = JSON.stringify(this[propName]);
        console.log(`${propName} changed. oldValue: ${oldValue} newValue: ${newValue}`);
    });
    return true;
}