【问题标题】:Web Components conversion happens too lateWeb 组件转换发生得太晚
【发布时间】:2020-06-26 20:02:25
【问题描述】:

在以下(简化的)代码中,第一个 Tester 实例使用预定义的模板,而第二个使用直接编码的模板。插值适用于第二个,因为 html 包含正确的 HTML 代码。在插值期间,第一个 Tester 实例仍然具有 的 innerHTML。如何更改代码概念以同时插入第一个示例?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Web Components Demo</title>
</head>
<body>
    <div id="tc"></div>
    <div id="tc2"></div>
    <script>
        class TestComponent extends HTMLElement {
            constructor () {
                super();
                this.attachShadow({mode: "open"});
                this.shadowRoot.appendChild(this.createTemplate().content.cloneNode(true));
            }
            createTemplate () {
                const template = document.createElement("template");
                template.innerHTML = "<h1>{{title}}</h1><p>{{text}}</p>";
                return template;
            }
        }
        window.customElements.define("test-component", TestComponent);

        class Tester {
            constructor ({selector, stuff, template}) {
                this.selector = Array.from(document.querySelectorAll(selector));
                this.template = template || null;
                this.stuff = stuff;
                this.render();
                this.interpolate();
            }
            render () {
                this.selector.forEach(s => {if (this.template) s.innerHTML = this.template});
            }
            interpolate () {
                this.selector.forEach(s => {
                    for (let key in this.stuff) { 
                        const regex = new RegExp(`{{ *${key} *}}`, "g");       
                        s.innerHTML = s.innerHTML.replace(regex, this.stuff[key]);;
                    } 
                });
            }
        }

        new Tester ({
            selector: "#tc",
            stuff: {title: "Test Title", text: "Lorem ipsum dolor sit amet"},
            template: "<test-component>"
        });

        new Tester ({
            selector: "#tc2",
            stuff: {title: "Title that works", text: "Lorem ipsum dolor sit amet"},
            template: "<h1>{{title}}</h1><p>{{text}}</p>"
        })
    </script>
</body>
</html>

【问题讨论】:

    标签: javascript interpolation web-component


    【解决方案1】:

    你的主要问题是:

    s.innerHTML = s.innerHTML.replace(regex, this.stuff[key]);
    

    s 是外部 DIV,而不是 &lt;test-component&gt; 内部HTML

    有效地销毁和重新创建 &lt;test-component&gt; 每个键

    因此constructor() 总是将您的默认模板再次设置为(元素)innerHTML:

    控制台记录您在第一个示例中运行的代码:

    注意

    constructor () {
        super();
        this.attachShadow({mode: "open"});       
        this.shadowRoot.appendChild(this.createTemplate().content.cloneNode(true));
    }
    createTemplate () {
        const template = document.createElement("template");
        template.innerHTML = "<h1>{{title}}</h1><p>{{text}}</p>";
        return template;
    }
    

    有点臃肿:您在模板中创建 HTML,然后添加 克隆的内容模板(即:HTML)到 empty shadowRoot innerHTML

    constructor () {
        super() // returns 'this'
           .attachShadow({mode: "open"}) // returns shadowRoot
           .innerHTML = "<h1>{{title}}</h1><p>{{text}}</p>";
    }
    

    只有在需要重用原始(模板)时才需要克隆(模板)

    解决方法:将 {{}} 解析移到元素内部

    <test-component id=One></test-component>
    <test-component id=Two></test-component>
    <script>
      window.customElements.define("test-component", class extends HTMLElement {
        constructor() {
          super().attachShadow({ mode: "open" });
          this.setTemplate(`<b>{{title}}</b> {{text}}`);
        }
        setTemplate(html, data = {}) {
          this.shadowRoot.innerHTML = html;
          this.parse(data);
        }
        parse(data) {
          let html = this.shadowRoot.innerHTML;
          for (let key in data) {
            const regex = new RegExp(`{{${key}}}`, "g");
            html = html.replace(regex, data[key]);
          }
          this.shadowRoot.innerHTML = html;
        }
      });
      One.parse({
        title: "Test Title",
        text: "Lorem ipsum dolor sit amet"
      })
      Two.setTemplate('<h4>{{title}}<h4>{{subtitle}}', {
        title: "Test Two",
        subtitle: "a Sub title"
      })
      let Three = document.createElement('test-component');
      Three.parse({//parsed IN shadowDOM innerHTML!
        title: "Title Three",
        text: "text three"
      })
      document.body.append(Three)
    </script>

    【讨论】:

    • 如果我想访问 HTML 组件,我该怎么做?有没有办法从另一个对象解析组件?
    • 带有mode:"open"的shadowDOM是...打开的...内容是document.querySelector(...).shadowRoot.innerHTML
    猜你喜欢
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-16
    • 1970-01-01
    • 1970-01-01
    • 2015-10-11
    相关资源
    最近更新 更多