您的replace行无效,因为它与HTML的确切结构不匹配,并且不会考虑代码之间的空白。您可以在replace来电中使用RegExp来处理空白,如下所示:
html.replace(/
\s*
\s*/, '');
// / start of the regex literal
//
a literal "
"
// \s any whitespace character
// * previous char, zero or more times
//
a literal "br"
// \s any whitespace character
// * previous char, zero or more times
// a literal "
" (with escaped slash)// / end of regex
这符合
内的会犯规。你可以制作越来越复杂的正则表达式来处理越来越多的深奥情境,但是that way lies madness和isn't possible in the general case。
相反,我们可以将生成的HTML拉入DocumentFragment。然后我们可以将它作为DOM树使用,而不是字符串:
const template = document.createElement('template');
template.innerHTML = html;
const fragment = template.content;
removeUselessNodes(fragment); // we'll need to write this one
HTMLTemplateElement可以帮助我们,因为我们可以为其innerHTML属性分配一个HTML字符串,并将其作为DocumentFragment从{{3}中拉出来属性。如果我们更改DocumentFragment的结构,则这些更改将反映在innerHTML属性中。*
*我无法找到支持我的文档,但它在Firefox和Chromium中适用于我。
现在我们需要实际删除那些[不]包含任何值的"不必要的空标签和标签。"我们将定义无用节点来帮助实现这一目标:
评论节点无用。
空白或仅包含空格的文本节点无用。
content仅包含无用节点或
元素的非void元素节点无用。
所有其他节点都不是无用的。
我们需要一个功能来识别和删除无用的节点。由于我们希望在整个树中搜索无用的节点,因此我们将在节点的子节点上递归调用该函数:
function removeUselessNodes(node) {
for (let i = node.childNodes.length - 1; i >= 0; --i) {
removeUselessNodes(node.childNodes.item(i));
}
我们反过来遍历子节点,因为Node.childNodes是一个实时列表,我们将从中删除元素。循环不知道我们正在进行的更改,如果我们前进,将会跳过元素。从列表末尾删除元素不会破坏向后迭代循环。我们首先执行递归调用,因为它可以更容易地检查最后一个无用节点条件。
通过所有树遍历,我们可以从无用节点条件开始。让我们逐一介绍它们:
评论节点无用。
这很容易。 Node有一个属性,表明其类型child nodes。我们可以检查并删除节点,如果它是评论:
if (node.nodeType === Node.COMMENT_NODE) {
node.remove();
return;
}
删除无用节点后立即返回;没有什么可做的。下一个:
空白或仅包含空格的文本节点无用。
" [E] mpty或仅包含[s]空格"是另一种表示"不包含非空格"的方式,我们可以使用nodeType进行测试。
if (
node.nodeType === Node.TEXT_NODE
&& !/\S/.test(node.textContent)
) {
node.remove();
return;
}
(\s是一个空白字符,\S(注意大小写)是一个非空白字符。)
最后一次测试需要一点点拆包:
RegExp.test仅包含无用节点或
元素的非void元素节点无用。
Void元素是不能生孩子的元素:和
之类的元素。他们并非无用;他们有自己的意义。出于我们的目的,非空白元素需要有意义的孩子才有意义。
本身只会在页面上留出一些空间。它的子文本节点是文本的来源。当
与其他节点相邻时,
并不是无用的,但它本身并不足以使其父节点有意义。
将其分解为单独的测试,我们得到
必须是元素节点
必须是无效的
子节点必须只包含无用的节点或if (
node.nodeType === Node.ELEMENT_NODE元素
我们之前测试了节点类型:
&& ![
'AREA',
'BASE',
'BR',
'COL',
'EMBED',
'HR',
'IMG',
'INPUT',
'LINK',
'META',
'PARAM',
'SOURCE',
'TRACK',
'WBR'
].includes(node.tagName)
没有方便的方法来检查JavaScript中的无效性,但HTML5规范包括child nodes我们可以使用a list of void elements属性进行检查:
由于我们已经从此节点中删除了所有无用的子节点,因此如果节点的所有子节点都是childNodes元素,则该节点将通过第三次测试。 NodeList是every,它没有length方法,但是使用0索引元素和&& Array.prototype.every.call(node.childNodes, n => n.tagName === 'BR')
) {
node.remove();
return;
}
}属性,我们可以调用数组&#39}。其上的Element.tagName方法:
fragment
这样,所有template.innerHTML个无用节点都被删除了。您可以从const adoptedNode = document.adoptNode(fragment);
document.querySelector('#destination').appendChild(adoptedNode);获取生成的HTML,也可以将其直接发送到every的其他元素:
var html = `
អ្នកធានា
ឈ្មោះ: ……………………………
អត្តសញ្ញាណប័ណ្ណលេខៈ………………...............
..........................................
ហត្ថលេខានិង ស្នាមមេដៃស្តាំ
`;
function removeUselessNodes(node) {
for (let i = node.childNodes.length - 1; i >= 0; --i) {
removeUselessNodes(node.childNodes.item(i));
}
if (node.nodeType === Node.COMMENT_NODE) {
node.remove();
return;
}
if (
node.nodeType === Node.TEXT_NODE
&& !/\S/.test(node.textContent)
) {
node.remove();
return;
}
if (
node.nodeType === Node.ELEMENT_NODE
&& ![
'AREA',
'BASE',
'BR',
'COL',
'EMBED',
'HR',
'IMG',
'INPUT',
'LINK',
'META',
'PARAM',
'SOURCE',
'TRACK',
'WBR'
].includes(node.tagName)
&& Array.prototype.every.call(node.childNodes, n => n.tagName === 'BR')
) {
node.remove();
return;
}
}
const template = document.createElement('template');
template.innerHTML = html;
const fragment = template.content;
removeUselessNodes(fragment);
document.querySelector('#rawHTML').value = template.innerHTML;
const adoptedNode = document.adoptNode(fragment);
document.querySelector('#destination').appendChild(adoptedNode);
全部放在一起:


#rawHTML {
width: 95vw;
height: 10em;
}
{{1}}