简体   繁体   English

如何将 append 模板元素映射到 shadow dom?

[英]How to append TEMPLATE Element to shadow dom?

When I try to append template to the shadow DOM, it only shows as a "#documentFragment", and never renders or copies the actual elements structured within the template.当我尝试将 append 模板转换为影子 DOM 时,它仅显示为“#documentFragment”,并且从不呈现或复制模板中结构的实际元素。

I spent hours trying to figure it out.我花了几个小时试图弄清楚。 The solution I found was to use:我找到的解决方案是使用:

  • template.firstElementChild.cloneNode(true); template.firstElementChild.cloneNode(true);

instead of:代替:

  • template.content.cloneNode(true);模板.content.cloneNode(true);

then, and only then, everything works as expected.然后,只有这样,一切都会按预期进行。

My question is, am I doing something wrong?我的问题是,我做错了吗?

 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>

TEMPLATES are only interesting if you need to make multiple copies or want to work in plain HTML + CSS as much as possible.仅当您需要制作多个副本或希望尽可能使用普通的 HTML + CSS 时, TEMPLATES才有意义。

Many Web Components show the usage:许多 Web 组件显示了用法:

const template = document.createElement("template");
template.innerHTML = "Hello World"

and then do:然后做:

constructor() {
    super();
    this._shadowRoot = this.attachShadow({ mode: "open" });
    this._shadowRoot.appendChild(template.content.cloneNode(true));
  }

Which, because the template is only used as a single "parent" container, you can write as:其中,因为模板仅用作单个“父”容器,您可以写成:

constructor() {
    super().attachShadow({ mode: "open" }).innerHTML = "Hello World";
  }

Note: super() returns this , and attachShadow() sets and returns this.shadowRoot ... for free注意: super()返回thisattachShadow()免费设置返回this.shadowRoot ...

Two types of TEMPLATES两种类型的模板

You can create a <TEMPLATE> in DOM , or you can create a template in Memory您可以在DOM中创建<TEMPLATE> ,也可以在Memory中创建template

Templates in Memory Memory 中的模板

9 out of 10 Memory-templates can be done with other HTMLElements as container, 10 个内存模板中有 9 个可以用其他 HTMLElements 作为容器来完成,
as is the case with your code, where FORM can be the main container.与您的代码一样, FORM可以是主容器。 No need for a template container.不需要template容器。

If you do build a template in memory, learn the value of append() over (the often misused) appendChild()如果您确实在 memory 中构建了一个模板,请了解append()的值而不是(经常被误用的) appendChild()

In Memory templates are great for making (many) alterations (with code)在 Memory 模板非常适合进行(许多)更改(带代码)

Templates in DOM DOM 中的模板

No need for trying to stuff HTML and CSS in JavaScript strings, you have a DOM in the HTML document!无需尝试在 JavaScript 字符串中填充HTMLCSS ,您在 Z4C4AD1FCA00E7A8AAED4ZDB 文档中有一个 DOM!
Use the <TEMPLATE> HTML Element.使用<TEMPLATE> HTML 元素。

Add shadowDOM <slot> to the mix and you will spent less time debugging JavaScript and more time writing semantic HTML.将 shadowDOM <slot>添加到组合中,您将花费更少的时间来调试 JavaScript,而将更多的时间用于编写语义 HTML。

DOM Templates are great for easy HTML and CSS editting (in your IDE with syntax highlighting) of more static HTML/CSS structures DOM Templates are great for easy HTML and CSS editting (in your IDE with syntax highlighting) of more static HTML/CSS structures


Here are both types of TEMPLATES with your code, which one is easier for a developer?这是您的代码的两种类型的模板,哪一种对开发人员来说更容易?

 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>

Note:笔记:

In the above code the <TEMPLATE>.content is moved to shadowDOM.在上面的代码中, <TEMPLATE>.content移到了 shadowDOM。

To re-use (clone) the <TEMPLATE> the code must be:要重用(克隆) <TEMPLATE> ,代码必须是:

super(document.getElementById("FormTwo").content.cloneNode(true));

Why your template.content failed为什么你的template.content失败了

Your code failed because with您的代码失败,因为

  const template = document.createElement('template');
  const form = document.createElement("form");
  template.appendChild(form);

template has no content template没有内容

TEMPLATE isn't a regular HTMLElement, you have to append to .content TEMPLATE不是常规的 HTMLElement,您必须将 append 转换为.content

  const template = document.createElement('template');
  const form = document.createElement("form");
  template.content.appendChild(form);

will work将工作

Most Web Component examples show:大多数 Web 组件示例显示:

  const template = document.createElement("template");
  template.innerHTML = "Hello World"

innerHTML sets .content under the hood innerHTML后台设置.content

Which explains why instead of:这解释了为什么而不是:

template.content.appendChild(form);

you can write:你可以写:

template.innerHTML = form.outerHTML;

A 'template' element is a special element that doesn't actually render right away( reference ). “模板”元素是一种特殊元素,实际上不会立即渲染( 参考)。 This is why appending the template produces nothing.这就是为什么附加模板不会产生任何结果。

template.firstElementChild.cloneNode means "get the child of the template (ie the form) and clone it", which is the same as just appending the form, which works (below). 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>

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

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