Web Components:是否有与 attributeChangedCallback 等效的属性?
Web Components: Is there an equivalent to attributeChangedCallback for properties?
您不应该在 HTML 元素属性中放置丰富的数据(对象、数组、函数)。相反,建议仅将丰富的数据放入属性中(根据 Google custom elements best practices article)。当更新这些属性时,我需要 运行 操作。我们有 observedAttributes
和 attributeChangedCallback
,但没有任何相似的属性。
假设我有一个 user
道具,上面有 name
、DoB
和 address
之类的东西。我以为我可以通过放一个铺位 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>
您不应该在 HTML 元素属性中放置丰富的数据(对象、数组、函数)。相反,建议仅将丰富的数据放入属性中(根据 Google custom elements best practices article)。当更新这些属性时,我需要 运行 操作。我们有 observedAttributes
和 attributeChangedCallback
,但没有任何相似的属性。
假设我有一个 user
道具,上面有 name
、DoB
和 address
之类的东西。我以为我可以通过放一个铺位 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>