JS获取含表格内容的<template> innerHTML异常问题排查
你遇到的问题其实是浏览器HTML解析器的自动修正行为导致的:
HTML规范里明确规定,<tbody>元素的直接子元素只能是<tr>(或相关表格行元素),而你写的{{ each(options.dossier.conteneurs) }}和{{ /each }}属于纯文本节点,并不是合法的<tbody>子元素。浏览器在解析<template>内部的HTML结构时,会自动把这些“非法”的文本节点移到<table>元素外面,最终导致你看到的结构错乱。
这里有几种可靠的解决方法,你可以根据自己的模板引擎选择合适的:
方法1:用注释包裹模板语法
把模板引擎的循环标签放在HTML注释里,这样浏览器解析时会忽略这些内容(不会当成非法节点移动),而你的模板引擎依然可以识别并解析注释内的语法:
<template id="fixedTemplate"> <table class="table table-xs table-hover"> <thead> <tr> <th>Conteneur</th> </tr> </thead> <tbody> <!-- {{ each(options.dossier.conteneurs) }} --> <tr> <td>{{ @this.numConteneur }}</td> </tr> <!-- {{ /each }} --> </tbody> </table> </template>
大部分主流模板引擎(比如Handlebars、Underscore模板等)都支持解析注释内的模板语法,如果你用的引擎不支持,可以查看它的配置文档开启相关功能。
方法2:用<script>标签替代<template>
将模板内容放在<script>标签中,并指定一个非JavaScript的type属性(比如text/x-handlebars-template),这样浏览器不会解析里面的HTML结构,会完整保留你的原始模板内容:
<script id="fixedTemplate" type="text/x-handlebars-template"> <table class="table table-xs table-hover"> <thead> <tr> <th>Conteneur</th> </tr> </thead> <tbody> {{ each(options.dossier.conteneurs) }} <tr> <td>{{ @this.numConteneur }}</td> </tr> {{ /each }} </tbody> </table> </script>
获取模板内容时,使用textContent而不是innerHTML:
const templateContent = document.getElementById('fixedTemplate').textContent;
这种方法是最稳妥的,因为完全绕过了浏览器的HTML结构解析,确保模板内容100%保留原始格式。
方法3:使用模板引擎的原生语法兼容(如果支持)
有些模板引擎提供了专门的语法来避免HTML解析冲突,比如Handlebars的{{#each}}块级语法(注意和你用的each(...)写法的区别),不过这取决于你使用的具体引擎是否支持这种更贴合HTML结构的语法。
内容的提问来源于stack exchange,提问作者Ben Gubler




