document.getElementsByTagName()包含未定义的项

时间:2017-08-11 13:44:04

标签: javascript html5 dom ecmascript-6

我写了一些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"> - 标记,它仍然可以正确呈现(请参阅代码示例)。

&#13;
&#13;
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;
&#13;
&#13;

如果我现在尝试运行此代码,则标识为<template>的模板中的第一个a - 标记会正确呈现,但第二个标记不会正常,只会抛出TypeError: templateElem is undefined第83行。将templateElems(相同范围)记录到控制台时,返回的对象长度为2,而第二个项目未定义。

为什么会这样,以及如何防止错误发生?

PS。:为方便起见,这里是github页面提供的普通代码,因此可以更轻松地使用调试器逐步完成代码:https://theplatzhalter.github.io/fiddle/templating/

0 个答案:

没有答案