繁体   English   中英

自定义元素未设置/获取属性

[英]custom elements not setting/getting attributes

如果我创建了两个自定义元素,并在另一个元素中创建了其中一个,则该属性不适用于第一个元素的新子元素。

 class Bar extends HTMLElement { constructor() { super(); const val = this.getAttribute('val') || 'no value'; const shadow = this.attachShadow({mode: 'open'}); const wrapper = document.createElement('div'); wrapper.innerHTML = ` <div class='bar'> <span>${val}</span> </div> `; shadow.appendChild(wrapper); } } customElements.define('x-bar', Bar); class Foo extends HTMLElement { constructor() { super(); const loop = this.getAttribute('loop') || 10; const shadow = this.attachShadow({mode: 'open'}); const wrapper = document.createElement('div'); for(let i=0; i<loop; i++){ const b = document.createElement('x-bar'); b.setAttribute('val', `value #${i}`); wrapper.appendChild(b); } shadow.appendChild(wrapper); } } customElements.define('x-foo', Foo); 
 <x-foo loop='3'></x-foo> 

我希望我的输出是

值#0

价值#1

价值#2

因为我已经像这样设置了attr b.setAttribute('val', value #${i});

但是我no value 3倍的no value

为什么要输入任何信息? 和/或解决方法,谢谢!

大多数人不了解Web组件的构造函数的规则:

这是官方文档:

https://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance

摘要是:

您的构造函数代码:

  • 作为构造函数中的第一条语句,必须对super()进行无参数调用。
  • 构造函数中的任何地方都不能有return语句。
  • 不得调用document.write()或document.open()。
  • 不得检查元素的属性。
  • 不得更改或添加任何属性或子级。

通常,应使用构造函数来设置初始状态和默认值,并设置事件侦听器以及可能的影子根。

总的来说,我同意@TJ Crowder,但是我将对Bar对象做一个小的修改:

 class Bar extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); } static get observedAttributes() { // Indicate that we want to be notified // when the `val` attribute is changed return ['val']; } connectedCallback() { // Render the initial value // when this element is placed into the DOM render(this.getAttribute('val')); } attributeChangedCallback(attrName, oldVal, newVal) { if (oldVal != newVal) { // If the value for the `val` attribute has changed // then re-render this element render(newVal); } } render(val = 'no value') { this.shadowRoot.innerHTML = ` <div class='bar'> <span>${val}</span> </div> `; } } customElements.define('x-bar', Bar); 

这使用了attributeChangedCallbackobservedAttributes的标准。 尽管覆盖setAttribute功能有效,但这并不是未来的证明。 如果将来更改setAttribute的API,则需要记住要修复您的组件。 而使用许多组件执行此操作会增加开发人员的债务。

 class Bar extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); // Render the blank DOM this.shadowRoot.innerHTML = '<div class="bar"><span>no value</span><div>'; this._span = this.shadowRoot.querySelector('span'); } static get observedAttributes() { // Indicate that we want to be notified // when the `val` attribute is changed return ['val']; } attributeChangedCallback(attrName, oldVal, newVal) { if (oldVal != newVal) { // If the value for the `val` attribute has changed // then insert the value into the `<span>` this._span.textContent = newVal || 'no value'; // OR: this._span.innerHTML = newVal || 'no value'; // But make sure someone has not tried to hit you // with a script attack. } } get val() { return this._span.textContent; } set val(newVal) { if (newVal == null || newVal === false || newVal === '') { this.removeAttribute('val'); } else { this.setAttribute('val', newVal); } } } customElements.define('x-bar', Bar); 

第二种方法不会重新呈现整个DOM,它只是将修改后的属性值插入<span>标记中。

它还提供了属性,因此您可以通过属性以及JavaScript来设置值:

var el = document.querySelector('x-bar');
if (el) {
  el.val = "A New String";
  setTimeout(()=>el.val = '';,2000);
}

直到构造函数被调用 ,才设置属性。 注意记录:

 class Bar extends HTMLElement { constructor() { super(); const val = this.getAttribute('val') || 'no value'; console.log("In constructor, val = " + val); const shadow = this.attachShadow({mode: 'open'}); const wrapper = document.createElement('div'); wrapper.innerHTML = ` <div class='bar'> <span>${val}</span> </div> `; shadow.appendChild(wrapper); } } customElements.define('x-bar', Bar); class Foo extends HTMLElement { constructor() { super(); const loop = this.getAttribute('loop') || 10; const shadow = this.attachShadow({mode: 'open'}); const wrapper = document.createElement('div'); for(let i=0; i<loop; i++){ console.log("Constructing..."); const b = document.createElement('x-bar'); console.log("Setting attribute"); b.setAttribute('val', `value #${i}`); wrapper.appendChild(b); } shadow.appendChild(wrapper); } } customElements.define('x-foo', Foo); 
 <x-foo loop='3'></x-foo> 

您需要将渲染逻辑移出构造函数,以便可以考虑构造后设置的属性。 也许通过重写setAttribute

 class Bar extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({mode: 'open'}); this.wrapper = document.createElement('div'); this.render(); // Though calling methods from the constructor isn't ideal shadow.appendChild(this.wrapper); } setAttribute(name, value) { super.setAttribute(name, value); if (name === "val") { this.render(); } } render() { const val = this.getAttribute('val') || 'no value'; this.wrapper.innerHTML = ` <div class='bar'> <span>${val}</span> </div> `; } } customElements.define('x-bar', Bar); class Foo extends HTMLElement { constructor() { super(); const loop = this.getAttribute('loop') || 10; const shadow = this.attachShadow({mode: 'open'}); const wrapper = document.createElement('div'); for(let i=0; i<loop; i++){ console.log("Constructing..."); const b = document.createElement('x-bar'); console.log("Setting attribute"); b.setAttribute('val', `value #${i}`); wrapper.appendChild(b); } shadow.appendChild(wrapper); } } customElements.define('x-foo', Foo); 
 <x-foo loop='3'></x-foo> 

但是,从构造函数中调用方法并不理想,您可能需要摆弄一些

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM