我写了一些ES6代码,应该能够从<script type="text/template" data-id="template-id"></script>
- 标签中读取模板,通过Handlebars传递它,并用给定ID的模板替换每个<template data-id="template-id" data-ctx='{"some": "json"}>
- 标签,同时还填写在上下文中进入模板中的{{ expressions }}
。
我在TemplateManager类中添加了依赖项,因此我可以在<template>
- 标记内添加<script type="text/template">
- 标记,它仍然可以正确呈现(请参阅代码示例)。
class TemplateManager {
constructor () {
this.templates = { }
this.dependencies = { }
}
addTemplate (id) {
if (this.templates.hasOwnProperty(id))
throw new Error('Template with ID "' + id + '" already exists!')
this.templates[id] = new Template(id)
}
removeTemplate (id) {
delete this.templates[id]
}
update (id) {
if (!this.templates.hasOwnProperty(id))
throw new Error('No template with ID "' + id + '" exists!')
this.templates[id].update()
if (this.dependencies.hasOwnProperty(id)) {
Object.keys(this.dependencies[id]).map((i) =>
this.update(this.dependencies[id][i])
)
}
}
addDependency (id, dependentOn) {
if (!this.dependencies.hasOwnProperty(id)) {
this.dependencies[id] = [ ]
}
Object.keys(dependentOn).map((i) => {
if (this.dependencies.hasOwnProperty(dependentOn[i]) && this.dependencies[dependentOn[i]].indexOf(id))
throw new Error('Circular dependencies detected!')
if (this.dependencies[id].indexOf(dependentOn[i]) == -1)
this.dependencies[id].push(dependentOn[i])
})
}
}
class Template {
constructor (id) {
this.id = id
this.template = Handlebars.compile(document.getElementById(id).innerHTML)
}
update () {
let templateElems = document.getElementsByTagName('template')
if (templateElems.length < 1)
return
Object.keys(templateElems).map((keyTmpl) => {
let templateElem = templateElems[keyTmpl],
div, ctx
if (!templateElem.attributes.hasOwnProperty('data-id')) {
throw new Error('A template tag needs a "data-id" attribute!')
throw new Error(templateElem)
}
ctx = templateElem.attributes.hasOwnProperty('data-ctx')
? JSON.parse(templateElem.attributes['data-ctx'].value)
: {}
if (templateElem.attributes['data-id'].value.trim() != this.id)
return
div = document.createElement('div')
div.innerHTML = this.template(ctx)
templateElem.parentNode.replaceChild(div, templateElem)
})
}
}
let manager = new TemplateManager()
manager.addTemplate('a')
manager.addTemplate('b')
manager.addDependency('a', [ 'b' ])
manager.update('a')
&#13;
<html>
<head>
<meta charset="utf-8" />
<title>Bug</title>
</head>
<body>
<template data-id="a" data-ctx='{"name":"World"}'></template>
<script type="text/template" id="a">
<h1>Hello, {{name}}!</h1>
<template data-id="b" data-ctx='{"place":"the Internet"}'></template>
<template data-id="b" data-ctx='{"place":"my house"}'></template>
</script>
<script type="text/template" id="b">
<h2>Welcome to {{place}}</h2>
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.10/handlebars.min.js"></script>
<script src="./script.js"></script>
</body>
</html>
&#13;
如果我现在尝试运行此代码,则标识为<template>
的模板中的第一个a
- 标记会正确呈现,但第二个标记不会正常,只会抛出TypeError: templateElem is undefined
第83行。将templateElems
(相同范围)记录到控制台时,返回的对象长度为2,而第二个项目未定义。
为什么会这样,以及如何防止错误发生?
PS。:为方便起见,这里是github页面提供的普通代码,因此可以更轻松地使用调试器逐步完成代码:https://theplatzhalter.github.io/fiddle/templating/