我试图了解新的HTML自定义元素。
我的目标是,在给定数据数组的基础上,创建n个自定义元素实例。例如,给定10个用户的列表,请创建10个用户html对象。
好-我在html中定义了一个自定义元素
HTML
<template-user>
<div class="user-name"></div>
</template-user>
然后我创建我的控制器
JS
class UserTemplate extends HTMLElement {
constructor(){
super();
this.username = this.querySelectorAll('[class="user-name"]')[0];
}
setName(name){
this.username.innerHtml = name;
}
}
customElements.define('template-user', UserTemplate);
页面加载正常,但是现在我对如何重用该元素感到困惑。如果我在做普通的老式学校课,我将有一个for循环,抽出一些HTML字符串并设置某些内容的innerHTML。但是现在我宁愿做类似的事情
for(let i = 0; i < users.length; i++){
let userTemplate = new UserTemplate();
userTemplate.setName(user.name);
// append to user list, etc..
}
当我尝试执行此操作时,它似乎几乎可以正常工作。但是找不到username
,即this.querySelectorAll
将返回null。只有当我尝试构造该元素的新实例时。那我应该如何创建新的自定义元素DOM对象?
答案 0 :(得分:3)
确保您了解Web组件的构造函数的要求和限制:
https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-conformance
4.13.2自定义元素构造函数的要求
创作自定义元素构造函数时,作者必须遵守以下符合性要求:
在元素创建过程中直接或间接地检查了其中的几个要求,如果不遵循这些要求,将导致无法由解析器或DOM API实例化的自定义元素。即使工作是在构造函数启动的微任务中完成的,也是如此,因为微任务检查点可能在构造后立即发生。
您可以进行以下更改:
class TemplateUser extends HTMLElement {
static get observedAttributes() {
return ['user-name'];
}
constructor(){
super();
this.attachShadow({mode:'open'});
this.shadowRoot.innerHTML = '<div></div>';
}
attributeChangedCallback(attrName, oldVal, newVal) {
if (oldVal !== newVal) {
this.shadowRoot.firstChild.innerHTML = newVal;
}
}
get userName() {
return this.getAttribute('user-name');
}
set userName(name) {
this.setAttribute('user-name', name);
}
}
customElements.define('template-user', TemplateUser);
setTimeout( function () {
var el = document.querySelector('[user-name="Mummy"]');
el.userName = "Creature from the Black Lagoon";
}, 2000);
<template-user user-name="Frank N Stein"></template-user>
<template-user user-name="Dracula"></template-user>
<template-user user-name="Mummy"></template-user>
此方法使用shadowDOM存储<div>
,然后通过user-name
属性或userName
属性设置值。
答案 1 :(得分:2)
但是找不到用户名,即this.querySelectorAll将返回null。
创建新实例时,新元素没有子元素,因此querySelectorAll
将返回一个空的NodeList。如果查询DOM并选择标记中定义的template-user
,则username
属性将引用您的div
元素。
如果您希望动态生成的template-user
元素默认具有一个<div class="user-name"></div>
子元素,则应在构造函数中创建并附加一个元素。
也可以使用.querySelector(...)
代替.querySelectorAll(...)[0]
来选择第一个匹配元素。
答案 2 :(得分:1)
当您使用new
通过Javascript创建自定义元素时,可以设置一些变量,这些变量将作为参数传递给constrcutor()
方法:
for (let user of users) {
document.body.appendChild( new UserTemplate(user.name) )
}
您可以获取它并将其保存在对象变量中,或者用作Shadow DOM中模板文字字符串中的变量。
class UserTemplate extends HTMLElement {
constructor(username){
super()
//this.username = username
this.attachShadow({ mode:'open' })
.innerHTML = `<div class="user-name"> ${username} </div>`
}
}
customElements.define('template-user', UserTemplate);
答案 3 :(得分:1)
您可以直接在JS中创建组件并分配属性
let templateUser = document.createElement('template-user');
templateUser.userName= 'Your name here';
document.body.appendChild(templateUser);
或与您类似的类似内容。 Google有一些文档here,大约描述了如何“使用JavaScript创建实例”的文档的约2/3。这可能非常强大,尤其是在像您的示例这样的for循环中