如何将 TEMPLATE 元素附加到阴影 dom?
How to append TEMPLATE Element to shadow dom?
当我尝试将模板附加到阴影 DOM 时,它仅显示为“#documentFragment”,而不会呈现或复制模板中结构化的实际元素。
我花了几个小时试图弄明白。我找到的解决方案是使用:
- template.firstElementChild.cloneNode(真);
而不是:
- template.content.cloneNode(真);
然后,也只有那时,一切都会按预期进行。
我的问题是,我做错了什么吗?
const template = document.createElement('template');
const form = document.createElement('form');
const gateway = document.createElement('fieldset');
const legend = document.createElement('legend');
gateway.appendChild(legend);
const username = document.createElement('input');
username.setAttribute('type', 'email');
username.setAttribute('name', 'username');
username.setAttribute('placeholder', 'email@address.com');
username.setAttribute('id', 'username');
gateway.appendChild(username);
const button = document.createElement('button');
button.setAttribute('type', 'button');
button.innerHTML = 'Next';
gateway.appendChild(button);
form.appendChild(gateway);
template.appendChild(form);
class UserAccount extends HTMLElement {
constructor() {
super();
const shadowDOM = this.attachShadow({
mode: 'open'
});
const clone = template.firstElementChild.cloneNode(true);
// This does not work
// const clone = template.content.cloneNode(true);
shadowDOM.appendChild(clone);
shadowDOM.querySelector('legend').innerHTML = this.getAttribute('api');
}
}
window.customElements.define('user-account', UserAccount);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<!-- <link rel="stylesheet" href="./css/main.css"> -->
<script src="./js/user-account.js" defer></script>
<title>Title</title>
</head>
<body>
<user-account api="/accounts"></user-account>
</body>
</html>
'template' 元素是一种特殊元素,实际上不会立即呈现 (reference)。这就是附加模板不会产生任何结果的原因。
template.firstElementChild.cloneNode
表示“获取模板的子项(即表单)并克隆它”,这与仅附加表单相同,后者有效(如下)。
const template = document.createElement('template');
const form = document.createElement('form');
const gateway = document.createElement('fieldset');
const legend = document.createElement('legend');
gateway.appendChild(legend);
const username = document.createElement('input');
username.setAttribute('type', 'email');
username.setAttribute('name', 'username');
username.setAttribute('placeholder', 'email@address.com');
username.setAttribute('id', 'username');
gateway.appendChild(username);
const button = document.createElement('button');
button.setAttribute('type', 'button');
button.innerHTML = 'Next';
gateway.appendChild(button);
form.appendChild(gateway);
template.appendChild(form);
class UserAccount extends HTMLElement {
constructor() {
super();
const shadowDOM = this.attachShadow({
mode: 'open'
});
shadowDOM.appendChild(form);
shadowDOM.querySelector('legend').innerHTML = this.getAttribute('api');
}
}
window.customElements.define('user-account', UserAccount);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<!-- <link rel="stylesheet" href="./css/main.css"> -->
<script src="./js/user-account.js" defer></script>
<title>Title</title>
</head>
<body>
<user-account api="/accounts"></user-account>
</body>
</html>
TEMPLATES
仅在您需要制作多份副本或希望尽可能以普通 HTML + CSS 工作时才有趣。
许多 Web 组件显示用法:
const template = document.createElement("template");
template.innerHTML = "Hello World"
然后做:
constructor() {
super();
this._shadowRoot = this.attachShadow({ mode: "open" });
this._shadowRoot.appendChild(template.content.cloneNode(true));
}
其中,因为模板只是作为一个单一的“父”容器,你可以这样写:
constructor() {
super().attachShadow({ mode: "open" }).innerHTML = "Hello World";
}
注:super()
returnsthis
和attachShadow()
集和returns this.shadowRoot
...免费
两种模板
你可以在DOM中创建一个<TEMPLATE>
,或者你可以在Memory[=]中创建一个template
130=]
内存中的模板
10 个中有 9 个 Memory-templates 可以用其他 HTML 元素作为容器来完成,
就像您的代码一样,其中 FORM
可以是主要容器。不需要 template
容器。
如果您确实在内存中构建模板,请了解 append()
的价值
(经常被误用)appendChild()
In Memory 模板非常适合进行(许多)更改(使用代码)
DOM
中的模板
无需尝试在 JavaScript 字符串中填充 HTML 和 CSS,您在 HTML 文档中有一个 DOM!
使用 <TEMPLATE>
HTML 元素。
将阴影DOM <slot>
添加到组合中,您将花费更少的时间调试 JavaScript 而将更多的时间用于编写语义 HTML.
DOM 模板非常适合轻松 HTML 和 CSS 编辑(在您的 IDE 中使用语法突出显示)更多静态 HTML/CSS 结构
这是您的代码的两种类型的模板,对于开发人员来说,哪一种更容易?
const form = document.createElement('form');
const gateway = document.createElement('fieldset');
const legend = document.createElement('legend');
const username = document.createElement('input');
username.setAttribute('type', 'email');
username.setAttribute('name', 'username');
username.setAttribute('placeholder', 'email@address.com');
username.setAttribute('id', 'username');
const button = document.createElement('button');
button.setAttribute('type', 'button');
button.innerHTML = 'Next';
gateway.append(legend,username,button);
form.appendChild(gateway);
class Form extends HTMLElement {
constructor(element) {
super().attachShadow({mode:'open'}).append(element);
}
connectedCallback() {
this.shadowRoot.querySelector('legend').innerHTML = this.getAttribute('api');
}
}
window.customElements.define('form-one', class extends Form {
constructor() {
super(form)
}
});
window.customElements.define('form-two', class extends Form {
constructor() {
super(document.getElementById("FormTwo").content);
}
});
<template id="FormTwo">
<form>
<fieldset>
<legend></legend>
<input type="email" name="username" placeholder="email@address.com" id="username">
<button type="button">Next</button>
</fieldset>
</form>
</template>
<form-one api="/accounts"></form-one>
<form-two api="/accounts"></form-two>
注:
在上面的代码中,<TEMPLATE>.content
移动 到阴影 DOM。
要re-use(克隆)<TEMPLATE>
,代码必须是:
super(document.getElementById("FormTwo").content.cloneNode(true));
为什么你的 template.content
失败了
您的代码失败,因为
const template = document.createElement('template');
const form = document.createElement("form");
template.appendChild(form);
template
有没有内容
TEMPLATE
不是常规 HTML 元素, 您必须附加到 .content
const template = document.createElement('template');
const form = document.createElement("form");
template.content.appendChild(form);
会起作用
大多数 Web 组件示例显示:
const template = document.createElement("template");
template.innerHTML = "Hello World"
innerHTML
设置 .content
底层
这解释了为什么不是:
template.content.appendChild(form);
你可以写:
template.innerHTML = form.outerHTML;
当我尝试将模板附加到阴影 DOM 时,它仅显示为“#documentFragment”,而不会呈现或复制模板中结构化的实际元素。
我花了几个小时试图弄明白。我找到的解决方案是使用:
- template.firstElementChild.cloneNode(真);
而不是:
- template.content.cloneNode(真);
然后,也只有那时,一切都会按预期进行。
我的问题是,我做错了什么吗?
const template = document.createElement('template');
const form = document.createElement('form');
const gateway = document.createElement('fieldset');
const legend = document.createElement('legend');
gateway.appendChild(legend);
const username = document.createElement('input');
username.setAttribute('type', 'email');
username.setAttribute('name', 'username');
username.setAttribute('placeholder', 'email@address.com');
username.setAttribute('id', 'username');
gateway.appendChild(username);
const button = document.createElement('button');
button.setAttribute('type', 'button');
button.innerHTML = 'Next';
gateway.appendChild(button);
form.appendChild(gateway);
template.appendChild(form);
class UserAccount extends HTMLElement {
constructor() {
super();
const shadowDOM = this.attachShadow({
mode: 'open'
});
const clone = template.firstElementChild.cloneNode(true);
// This does not work
// const clone = template.content.cloneNode(true);
shadowDOM.appendChild(clone);
shadowDOM.querySelector('legend').innerHTML = this.getAttribute('api');
}
}
window.customElements.define('user-account', UserAccount);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<!-- <link rel="stylesheet" href="./css/main.css"> -->
<script src="./js/user-account.js" defer></script>
<title>Title</title>
</head>
<body>
<user-account api="/accounts"></user-account>
</body>
</html>
'template' 元素是一种特殊元素,实际上不会立即呈现 (reference)。这就是附加模板不会产生任何结果的原因。
template.firstElementChild.cloneNode
表示“获取模板的子项(即表单)并克隆它”,这与仅附加表单相同,后者有效(如下)。
const template = document.createElement('template');
const form = document.createElement('form');
const gateway = document.createElement('fieldset');
const legend = document.createElement('legend');
gateway.appendChild(legend);
const username = document.createElement('input');
username.setAttribute('type', 'email');
username.setAttribute('name', 'username');
username.setAttribute('placeholder', 'email@address.com');
username.setAttribute('id', 'username');
gateway.appendChild(username);
const button = document.createElement('button');
button.setAttribute('type', 'button');
button.innerHTML = 'Next';
gateway.appendChild(button);
form.appendChild(gateway);
template.appendChild(form);
class UserAccount extends HTMLElement {
constructor() {
super();
const shadowDOM = this.attachShadow({
mode: 'open'
});
shadowDOM.appendChild(form);
shadowDOM.querySelector('legend').innerHTML = this.getAttribute('api');
}
}
window.customElements.define('user-account', UserAccount);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<!-- <link rel="stylesheet" href="./css/main.css"> -->
<script src="./js/user-account.js" defer></script>
<title>Title</title>
</head>
<body>
<user-account api="/accounts"></user-account>
</body>
</html>
TEMPLATES
仅在您需要制作多份副本或希望尽可能以普通 HTML + CSS 工作时才有趣。
许多 Web 组件显示用法:
const template = document.createElement("template");
template.innerHTML = "Hello World"
然后做:
constructor() {
super();
this._shadowRoot = this.attachShadow({ mode: "open" });
this._shadowRoot.appendChild(template.content.cloneNode(true));
}
其中,因为模板只是作为一个单一的“父”容器,你可以这样写:
constructor() {
super().attachShadow({ mode: "open" }).innerHTML = "Hello World";
}
注:super()
returnsthis
和attachShadow()
集和returns this.shadowRoot
...免费
两种模板
你可以在DOM中创建一个<TEMPLATE>
,或者你可以在Memory[=]中创建一个template
130=]
内存中的模板
10 个中有 9 个 Memory-templates 可以用其他 HTML 元素作为容器来完成,
就像您的代码一样,其中 FORM
可以是主要容器。不需要 template
容器。
如果您确实在内存中构建模板,请了解 append()
的价值
(经常被误用)appendChild()
In Memory 模板非常适合进行(许多)更改(使用代码)
DOM
中的模板无需尝试在 JavaScript 字符串中填充 HTML 和 CSS,您在 HTML 文档中有一个 DOM!
使用 <TEMPLATE>
HTML 元素。
将阴影DOM <slot>
添加到组合中,您将花费更少的时间调试 JavaScript 而将更多的时间用于编写语义 HTML.
DOM 模板非常适合轻松 HTML 和 CSS 编辑(在您的 IDE 中使用语法突出显示)更多静态 HTML/CSS 结构
这是您的代码的两种类型的模板,对于开发人员来说,哪一种更容易?
const form = document.createElement('form');
const gateway = document.createElement('fieldset');
const legend = document.createElement('legend');
const username = document.createElement('input');
username.setAttribute('type', 'email');
username.setAttribute('name', 'username');
username.setAttribute('placeholder', 'email@address.com');
username.setAttribute('id', 'username');
const button = document.createElement('button');
button.setAttribute('type', 'button');
button.innerHTML = 'Next';
gateway.append(legend,username,button);
form.appendChild(gateway);
class Form extends HTMLElement {
constructor(element) {
super().attachShadow({mode:'open'}).append(element);
}
connectedCallback() {
this.shadowRoot.querySelector('legend').innerHTML = this.getAttribute('api');
}
}
window.customElements.define('form-one', class extends Form {
constructor() {
super(form)
}
});
window.customElements.define('form-two', class extends Form {
constructor() {
super(document.getElementById("FormTwo").content);
}
});
<template id="FormTwo">
<form>
<fieldset>
<legend></legend>
<input type="email" name="username" placeholder="email@address.com" id="username">
<button type="button">Next</button>
</fieldset>
</form>
</template>
<form-one api="/accounts"></form-one>
<form-two api="/accounts"></form-two>
注:
在上面的代码中,<TEMPLATE>.content
移动 到阴影 DOM。
要re-use(克隆)<TEMPLATE>
,代码必须是:
super(document.getElementById("FormTwo").content.cloneNode(true));
为什么你的 template.content
失败了
您的代码失败,因为
const template = document.createElement('template');
const form = document.createElement("form");
template.appendChild(form);
template
有没有内容
TEMPLATE
不是常规 HTML 元素, 您必须附加到 .content
const template = document.createElement('template');
const form = document.createElement("form");
template.content.appendChild(form);
会起作用
大多数 Web 组件示例显示:
const template = document.createElement("template");
template.innerHTML = "Hello World"
innerHTML
设置 .content
底层
这解释了为什么不是:
template.content.appendChild(form);
你可以写:
template.innerHTML = form.outerHTML;