Web组件:是否有等同于attributeChangedCallback的属性?

时间:2019-05-01 07:14:27

标签: javascript callback web-component object-properties

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

假设我有一个user道具,上面有nameDoBaddress之类的道具。我以为我可以通过放置双层塞子 ala

来欺骗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};
})

1 个答案:

答案 0 :(得分:2)

您可以使用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>