javascript - Web 组件转换发生得太晚
问题描述
在以下(简化的)代码中,第一个 Tester 实例使用预定义的模板,而第二个使用直接编码的模板。插值适用于第二个,因为 html 包含正确的 HTML 代码。在插值期间,第一个 Tester 实例仍然具有 <test-component> 的 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>
解决方案
你的主要问题是:
s.innerHTML = s.innerHTML.replace(regex, this.stuff[key]);
s
是外部 DIV,而不是内部<test-component>
HTML
有效地销毁和重新创建 <test-component>
每个键
因此,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)添加到空的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>
推荐阅读
- python - 切片时有没有办法从列表的末尾到开头?
- python - 如何更改硒中的IP地址?
- sql - Oracle SQL 比较不到两天的日期
- django - 如何根据使用的应用程序更改 Django 管理中的查看站点链接?
- python - Feedparser 到数据框不输出所有列
- sql-server - 如何将 ADFS 连接到不同域中的 SQL 数据库?
- android - 引起:kotlin.UninitializedPropertyAccessException:lateinit 属性对话框尚未初始化
- html - 如何在 Go 中使用 struct 中的数据生成 html
- flutter - 参数“id”是必需的。当 id 为自动增量时
- asp.net-core - 将 .NET Core 2.2 Web 应用程序移动到装有 Windows 10 的新计算机后,它失败了