Web Components:是否有与 attributeChangedCallback 等效的属性?

Web Components: Is there an equivalent to attributeChangedCallback for properties?

您不应该在 HTML 元素属性中放置丰富的数据(对象、数组、函数)。相反,建议仅将丰富的数据放入属性中(根据 Google custom elements best practices article)。当更新这些属性时,我需要 运行 操作。我们有 observedAttributesattributeChangedCallback,但没有任何相似的属性。

假设我有一个 user 道具,上面有 nameDoBaddress 之类的东西。我以为我可以通过放一个铺位 setter a la

来欺骗 observedAttributes
set user(val) {
  return;
}

没用。 return this.user = val 给出一个无限循环。

此时我唯一的想法是有一个名为 _user 的 属性,它在每次更改时简单地设置为 [Object object],这会触发我真正想要的更改。不过不是很喜欢。

更新:这就是我目前正在做的事情

user-info.js中:

class UserInfo extends HTMLElement {
  connectedCallback() {
    subscribers.push({ element: this, props: ['user'] });
    this._user = state.user;
    this.render();
  }
  static get observedAttributes() {
    return ['user'];
  }
  attributeChangedCallback(name, oldValue, newValue) {
    this.render();
  }
  get user() {
    return this._user;
  }
  set user(val) {
    if (JSON.stringify(val) !== JSON.stringify(this._user)) {
      this._user = val;
      return this.setAttribute('user', val);
    }
  }
  render() {
    this.innerHTML = `<span>${this._user.name}</span> was born on <span>${this._user.dob}</span>`;
  }
}

main.js中:

document.querySelector('.actions--user').addEventListener('input', e => {
  state.user = {...state.user, [e.target.dataset.action]: e.target.value};
})

您可以使用 Proxy 检测对象的更新属性。

customElements.define( 'user-info', class extends HTMLElement {
  connectedCallback() {
    this._user = {
        name: 'Bruno',
        dob: '1/1/2000'
    }
    this.render();
    this._proxy = new Proxy( this._user, {
        set: ( obj, prop, val ) => {
            if ( prop === 'name' ) 
                if ( this._user.name !== val ) {
                    console.log( 'username updated to ' + val )
                    this._user.name = val
                    this.render()
                }
        }
    } )
  }
  get user() {
    return this._proxy
  }
  set user(val) {
    if (JSON.stringify(val) !== JSON.stringify(this._user)) {
      this._user = val
      this.render()
    }
  }
  render() {
    this.innerHTML = `<span>${this._user.name}</span> was born on <span>${this._user.dob}</span>`
  }
} )
<user-info id=ui></user-info><br>
<label>Name: <input oninput="ui.user.name=this.value"></label>


或者,您可以定义一个用户 object / class,其中包含可与自定义元素交互的设置器。

class User {
  constructor( elem ) {
    this._elem = elem
    this._name = 'Bruno'
    this._dob = '1/1/2000'
  }
  set name( val ) {
    if ( val !== this._name ) {
      this._name = val
      this._elem.render()
    }
    return false
  }
  get name() {
    return this._name
  }
  get dob() {
    return this._dob
  }
  update( obj ) {
    this._name = obj.name
    this._dob = obj.dob
  }
}

class UserInfo extends HTMLElement {
  connectedCallback() {
    this._user = new User( this )
    this.render()
  }
  get user() {
    return this._user
  }
  set user(val) {
    this._user.update( val )
    this.render()
  }
  render() {
    this.innerHTML = `<span>${this._user.name}</span> was born on <span>${this._user.dob}</span>`
  }
}

customElements.define( 'user-info', UserInfo )
<user-info id=ui></user-info><br>
<label>Name: <input oninput="ui.user.name=this.value"></label>