HTML <template>元素和JavaScript模板字面量的区别

8

Mozilla表示Web components由三个主要技术组成:

  1. 自定义元素
  2. Shadow DOM
  3. HTML模板

在ECMAscript的模板文字的背景下,编号3“HTML模板”是否必要?

看看我从James Milner那里得到的这个例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Web Component</title>
    <script type="text/javascript">
    // We define an ES6 class that extends HTMLElement
    class CounterElement extends HTMLElement{
            constructor() {
                    super();
                    // Initialise the counter value
                    this.counter = 0;

                    // We attach an open shadow root to the custom element
                    const shadowRoot= this.attachShadow({mode: 'open'});

                    // We define some inline styles using a template string
                    const styles=`
                            :host {
                                    position: relative;
                                    font-family: sans-serif;
                            }

                            #counter-increment, #counter-decrement {
                                    width: 60px;
                                    height: 30px;
                                    margin: 20px;
                                    background: none;
                                    border: 1px solid black;
                            }

                            #counter-value {
                                    font-weight: bold;
                            }
                    `;

                    // We provide the shadow root with some HTML
                    shadowRoot.innerHTML = `
                            <style>${styles}</style>
                            <h3>Counter</h3>
                            <slot name='counter-content'>Button</slot>
                            <button id='counter-increment'> - </button>
                            <span id='counter-value'> 0 </span>
                            <button id='counter-decrement'> + </button>
                    `;

                    // We can query the shadow root for internal elements
                    // in this case the button
                    this.incrementButton = this.shadowRoot.querySelector('#counter-increment');
                    this.decrementButton = this.shadowRoot.querySelector('#counter-decrement');
                    this.counterValue = this.shadowRoot.querySelector('#counter-value');

                    // We can bind an event which references one of the class methods
                    this.incrementButton.addEventListener("click", this.decrement.bind(this));
                    this.decrementButton.addEventListener("click", this.increment.bind(this));

            }
            increment() {
                    this.counter++
                    this.invalidate();
            }
            decrement() {
                    this.counter--
                    this.invalidate();
            }
            // Call when the counter changes value
            invalidate() {
                    this.counterValue.innerHTML = this.counter;
            }
    }
    // This is where the actual element is defined for use in the DOM
    customElements.define('counter-element', CounterElement);
    </script>
</head>
<body>
    <counter-element></counter-element>
</body>
</html>

注意他没有使用HTML模板,而是使用ecmascript模板字面量来设置shadowRoot的innerHTML。
此后,他使用querySelector获取shadowRoot的内部元素,并最终为增量和减量按钮添加事件侦听器。
如果您使用HTML模板而不是ecmascript模板字面量,这会给您带来什么好处?
从概念上讲,我很难找到一个情况,我更喜欢使用HTML模板元素而不是Ecmascript模板字面量。
请给予建议。

2
另一个问题是,模板文字很容易被转译(使用Babel和polyfill,任何重要项目都会有),这样项目就可以在IE中工作。而<template>元素似乎不受IE支持。 - CertainPerformance
2
一个反对意见是保持你的HTML为HTML,关注点分离等等。如果你想改变你的文档结构,改变你的HTML文档,而不是javascript。这对我来说更直观。缺乏IE对模板的支持确实很糟糕。有一种解决方法是使用<script type="text/template" id="postTemplate">代替<template>。有关jquery的示例,请参见:https://stackoverflow.com/questions/52376527/populate-grid-div-p-with-json-data-file/52376863#52376863。实际上并不需要jQuery,这只是我找到的第一个例子。 - Jon P
1
可能是Web组件中的HTML模板和模板字符串的重复问题。 - Supersharp
模板字面量是JS中的一种语法糖,与HTML功能无关。 - Bergi
@LonnieBest 如果您动态生成<template>元素,那么您仍然在使用Web组件技术的一部分吗?不,模板字面量不是“存储库”,它们是js语法。您可以使用普通字符串字面量实现完全相同的效果,或者从其他地方加载/生成字符串。 - Bergi
显示剩余5条评论
1个回答

3
模板标签对于Web组件本身并不是“必需”的。在 HTML Imports 被推广时,它可能更有意义,允许导入和重用HTML片段,但这已经停止了。在那里,您可以导入模板并重新使用它。
值得注意的是,规范被设计为独立的,也可以相互独立地使用,这使它们非常灵活。HTML 标签具有超出 Web 组件领域的用例;它很有用,因为它允许您定义一段标记,直到稍后通过 JavaScript 实例化才会呈现。确实,您可以使用模板而不使用任何其他规范(自定义元素、影子DOM 等)。
模板标签当然可以与其他规范一起使用。例如,在所示示例中,我们可以使用它来使代码更少命令式编写并将焦点放在标记上:
 <template id="counterTemplate">
   <style>
         :host {
             position: relative;
             font-family: sans-serif;
         }

         #counter-increment, #counter-decrement {
             width: 60px;
             height: 30px;
             margin: 20px;
             background: none;
             border: 1px solid black;
          }

         #counter-value {
             font-weight: bold;
         }
   </style>
   <h3>Counter</h3>
   <slot name='counter-content'>Button</slot>
   <button id='counter-increment'> - </button>
   <span id='counter-value'> 0 </span>
   <button id='counter-decrement'> + </button>
</template>

然后在 JavaScript 中像这样使用:

   const template = document.querySelector('#counterTemplate');
   const counter = document.cloneNode(template);
   shadowRoot.appendChild(counter);

这里的缺点是需要在实例化之前在DOM中存在模板,因为它依赖于#counterTemplate模板的存在。在某些方面,这使得自定义元素不太可移植,因此使用模板文字可能更理想。我还没有测试过两者的性能,但我的直觉告诉我,模板可能会更高效。
免责声明:本人撰写了原始博客文章。

事实上,这将使得可移植性更加繁琐。 - Lonnie Best
另一个我没有找到信息的话题是将样式放置在影子根中时的内存消耗 - Lonnie Best
1
我在这里找到了一个有趣的视频,讲解ES6模板字面量:https://www.youtube.com/watch?v=asRu9MPojFE - Milap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接