【问题标题】:How to observe property changes with LitElement如何使用 LitElement 观察属性变化
【发布时间】:2018-10-28 17:18:30
【问题描述】:

我不知道如何观察 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 lit-element


    【解决方案1】:

    版本 0.6.0+

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

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

    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);
    

    【讨论】:

    • changedProperties 参数是什么?它是已更改属性的映射,即{ 'name': 'foo', 'value': 10 },还是只是值10?如果您有多个属性怎么办?
    • @LukeTO'Brien 它不是一个“地图”对象,它是一个真实的Map。所以你会写changedProperties.has('name')。通常不要使用.get(),因为这些值是previous 值。访问当前值,例如 this.name
    【解决方案2】:

    我个人重写了“requestUpdate”方法,以便在渲染之前了解更改。

    我的用例是拦截“标签”属性的更改以触发异步数据请求。

    下面的片段(在 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,然后另一次在数据可用时加载。

    【讨论】:

      【解决方案3】:

      属性 'hasChanged' 选项:

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

      hasChanged 应该返回 true 来更新元素。

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

      看看here

      生命周期方法:更新

      有一个名为“updated”的生命周期方法,每次任何属性更改时都会触发。

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

      查看“更新”文档here

      【讨论】:

        【解决方案4】:

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

        这在 LitElement readme 中有说明:

        对更改做出反应:LitElement 通过异步渲染对属性和属性的更改做出反应,确保更改是批处理的。这样可以减少开销并保持一致的状态。

        例如:

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

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

        【讨论】:

          【解决方案5】:

          我从 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
          

          【讨论】:

          • 此解决方案已过时 - @UNREALprogrammer 的答案目前是正确的。
          • @mattlohkamp 看起来他们的名字已更改或答案已被删除。
          【解决方案6】:

          实现 shouldUpdate() 方法。 Source here.

          控制是否应进行更新。实施shouldUpdate 以指定哪些属性更改应导致更新。默认情况下,此方法始终返回 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;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-05-27
            • 1970-01-01
            • 2020-01-13
            • 2017-04-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多