自定义元素不拾取属性
Custom element not picking up attributes
我正在尝试查看自定义元素及其工作原理,虽然 MDN 上的示例工作正常,但我似乎无法自己复制它们。
MDN 文章是 here。
This 是来自 MDN 的工作示例。
我的问题是我似乎永远无法将属性传递到我的组件中,它们总是以 null 形式出现,而不是传递参数的值。
我的 JS 是 (test.js)
class PopUpInfo extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
// Create a shadow root
const shadow = this.attachShadow({mode: 'open'});
// Create spans
const wrapper = document.createElement('span');
const info = document.createElement('span');
// Take attribute content and put it inside the info span
const text = this.getAttribute('foo'); // <-- this always returns null
info.textContent = `(${text})`;
shadow.appendChild(wrapper);
wrapper.appendChild(info);
}
}
// Define the new element
customElements.define('popup-info', PopUpInfo);
还有我的Html:
<html>
<head>
<script src="test.js"></script>
</head>
<body>
<hr>
<popup-info foo="Hello World"></popup-info>
<hr>
</body>
</html>
我希望在屏幕上看到的是文字
(Hello World)
但我所看到的只是
(null)
当我调试时,我可以看到 this.attributes
的长度为 0,因此它没有被传入。
有人在创建自定义元素时见过这个吗?
您在 HTML 中的脚本导入中缺少延迟属性,并且它没有正确加载,这就是问题所在。 defer属性允许脚本在页面解析后执行
class PopUpInfo extends HTMLElement {
constructor() {
// Always call super first in constructor
super()
// Create a shadow root
const shadow = this.attachShadow({ mode: 'open' })
// Create spans
const wrapper = document.createElement('span')
const info = document.createElement('span')
// Take attribute content and put it inside the info span
const text = this.getAttribute('foo') // <-- this always returns null
info.textContent = `(${text})`
shadow.appendChild(wrapper)
wrapper.appendChild(info)
}
}
// Define the new element
customElements.define('popup-info', PopUpInfo)
<html>
<head>
<script src="app.js" defer></script>
</head>
<body>
<hr />
<popup-info foo="Hello World"></popup-info>
<hr />
</body>
</html>
尽管当我在此处尝试 运行 片段时您的示例似乎 运行 不错,但我仍然想提出改进建议。
使用 observedAttributes
静态 getter 定义组件应关注的属性列表。当属性值已更改且属性名称在列表中时,将调用 attributeChangedCallback
回调。在那里你可以断言每当你的属性值被改变时要做什么的逻辑。
在这种情况下,您可以构建您想要的字符串。这也有副作用,每当再次更改属性值时,字符串将被更新。
class PopUpInfo extends HTMLElement {
/**
* Observe the foo attribute for changes.
*/
static get observedAttributes() {
return ['foo'];
}
constructor() {
super();
const shadow = this.attachShadow({
mode: 'open'
});
const wrapper = document.createElement('span');
const info = document.createElement('span');
wrapper.classList.add('wrapper');
wrapper.appendChild(info);
shadow.appendChild(wrapper);
}
/**
* Returns the wrapper element from the shadowRoot.
*/
get wrapper() {
return this.shadowRoot.querySelector('.wrapper')
}
/**
* Is called when observed attributes have a changed value.
*/
attributeChangedCallback(attrName, oldValue, newValue) {
switch(attrName) {
case 'foo':
this.wrapper.textContent = `(${newValue})`;
break;
}
}
}
// Define the new element
customElements.define('popup-info', PopUpInfo);
<html>
<head>
<script src="test.js"></script>
</head>
<body>
<hr>
<popup-info foo="Hello World"></popup-info>
<hr>
</body>
</html>
让埃米尔保持他的正确答案。
只是为了表明可能有替代的和更短的符号:
customElements.define('popup-info', class extends HTMLElement {
static get observedAttributes() {
return ['foo'];
}
constructor() {
const wrapper = document.createElement('span');
super().attachShadow({mode:'open'})// both SETS and RETURNS this.shadowRoot
.append(wrapper);
this.wrapper = wrapper;
}
attributeChangedCallback(name, oldValue, newValue) {
switch(name) {
case 'foo':
this.wrapper.textContent = `(${newValue})`;
break;
}
}
});
<popup-info
foo="Hello World"
onclick="this.setAttribute('foo','Another world')"
>
</popup-info>
我正在尝试查看自定义元素及其工作原理,虽然 MDN 上的示例工作正常,但我似乎无法自己复制它们。
MDN 文章是 here。
This 是来自 MDN 的工作示例。
我的问题是我似乎永远无法将属性传递到我的组件中,它们总是以 null 形式出现,而不是传递参数的值。
我的 JS 是 (test.js)
class PopUpInfo extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
// Create a shadow root
const shadow = this.attachShadow({mode: 'open'});
// Create spans
const wrapper = document.createElement('span');
const info = document.createElement('span');
// Take attribute content and put it inside the info span
const text = this.getAttribute('foo'); // <-- this always returns null
info.textContent = `(${text})`;
shadow.appendChild(wrapper);
wrapper.appendChild(info);
}
}
// Define the new element
customElements.define('popup-info', PopUpInfo);
还有我的Html:
<html>
<head>
<script src="test.js"></script>
</head>
<body>
<hr>
<popup-info foo="Hello World"></popup-info>
<hr>
</body>
</html>
我希望在屏幕上看到的是文字
(Hello World)
但我所看到的只是
(null)
当我调试时,我可以看到 this.attributes
的长度为 0,因此它没有被传入。
有人在创建自定义元素时见过这个吗?
您在 HTML 中的脚本导入中缺少延迟属性,并且它没有正确加载,这就是问题所在。 defer属性允许脚本在页面解析后执行
class PopUpInfo extends HTMLElement {
constructor() {
// Always call super first in constructor
super()
// Create a shadow root
const shadow = this.attachShadow({ mode: 'open' })
// Create spans
const wrapper = document.createElement('span')
const info = document.createElement('span')
// Take attribute content and put it inside the info span
const text = this.getAttribute('foo') // <-- this always returns null
info.textContent = `(${text})`
shadow.appendChild(wrapper)
wrapper.appendChild(info)
}
}
// Define the new element
customElements.define('popup-info', PopUpInfo)
<html>
<head>
<script src="app.js" defer></script>
</head>
<body>
<hr />
<popup-info foo="Hello World"></popup-info>
<hr />
</body>
</html>
尽管当我在此处尝试 运行 片段时您的示例似乎 运行 不错,但我仍然想提出改进建议。
使用 observedAttributes
静态 getter 定义组件应关注的属性列表。当属性值已更改且属性名称在列表中时,将调用 attributeChangedCallback
回调。在那里你可以断言每当你的属性值被改变时要做什么的逻辑。
在这种情况下,您可以构建您想要的字符串。这也有副作用,每当再次更改属性值时,字符串将被更新。
class PopUpInfo extends HTMLElement {
/**
* Observe the foo attribute for changes.
*/
static get observedAttributes() {
return ['foo'];
}
constructor() {
super();
const shadow = this.attachShadow({
mode: 'open'
});
const wrapper = document.createElement('span');
const info = document.createElement('span');
wrapper.classList.add('wrapper');
wrapper.appendChild(info);
shadow.appendChild(wrapper);
}
/**
* Returns the wrapper element from the shadowRoot.
*/
get wrapper() {
return this.shadowRoot.querySelector('.wrapper')
}
/**
* Is called when observed attributes have a changed value.
*/
attributeChangedCallback(attrName, oldValue, newValue) {
switch(attrName) {
case 'foo':
this.wrapper.textContent = `(${newValue})`;
break;
}
}
}
// Define the new element
customElements.define('popup-info', PopUpInfo);
<html>
<head>
<script src="test.js"></script>
</head>
<body>
<hr>
<popup-info foo="Hello World"></popup-info>
<hr>
</body>
</html>
让埃米尔保持他的正确答案。
只是为了表明可能有替代的和更短的符号:
customElements.define('popup-info', class extends HTMLElement {
static get observedAttributes() {
return ['foo'];
}
constructor() {
const wrapper = document.createElement('span');
super().attachShadow({mode:'open'})// both SETS and RETURNS this.shadowRoot
.append(wrapper);
this.wrapper = wrapper;
}
attributeChangedCallback(name, oldValue, newValue) {
switch(name) {
case 'foo':
this.wrapper.textContent = `(${newValue})`;
break;
}
}
});
<popup-info
foo="Hello World"
onclick="this.setAttribute('foo','Another world')"
>
</popup-info>