我怎么能"合并”;两个HTML标签
How can I "merge" two HTML tags via JavaScript
这是我的HTML"沙盒":
<p>1 2 3</p>
<span id="myid">
<span id="mytext">
<p>4 5 6</p>
<p>7 8 9</p>
<p>10 11 12</p>
</span>
</span>
<p>13 14 15</p>
我想相应地"合并"p标签:
(为了更容易看到,我在进行更改的地方添加了一个减号:)
<p>1 2 3 -
<span id="myid">
<span id="mytext">
- 4 5 6</p>
<p>7 8 9</p>
<p>10 11 12 -
</span>
</span>
- 13 14 15</p>
在我添加减号的每一个地方,我实际上都剥离了一个<p>
或</p>
标签,在两个段落元素之间进行合并(在1 2 3和4 5 6之间以及在10 11 12和13 14 15之间)-(此合并只是为了实现123-456和101112-131415的内联显示)
如何使用"原始"JavaScript(请不要使用库)实现此结果
注:我试着创建一些东西,但它花了我80行代码——我相信有更好的方法可以做到这一点
编辑:Jon Hanna在他的评论中提到,我可以像这样使用正确的HTML(作为JavaScript的结果):
<p>1 2 3 <span class="myclass mytext">4 5 6</span></p>
<p class="myclass mytext">7 8 9</p>
<p><span class="myclass mytext"10 11 12</span> 13 14 15</p>
我不确定你想要实现什么,但我可以告诉你,使用JavaScript很难实现你所要求的。这主要是因为HTML是无效的。
让我们首先了解为什么HTML无效。浏览器解析HTML时,会构建DOM节点的嵌套树。你的第一个例子可以这样表示:
<p>
- 1 2 3
<span id="myid">
<span id="mytext">
<p>
- 4 5 6
<p>
- 7 8 9
<p>
- 10 11 12
<p>
- 13 14 15
使用JavaScript和DOM,您可以遍历并操作这棵树。您可以将来自各种<p>
标记的文本节点组合在一个单独的<p>
标记中,而不会出现问题。但是您将无法创建第二个示例的结构。它的形状根本不像DOM树,所以不能使用DOM来创建HTML。
像Jon Hanna解释的那样,将HTML操作成第二个示例形状的唯一方法是通过innerHTML
。好消息是浏览器将始终将无效的HTML更正为有效的DOM结构。坏消息是,每个浏览器的操作方式都不同,所以你永远不知道最终会得到什么。
唯一真正的解决方案是重新思考您的HTML结构,就像您在最近的编辑中所做的那样。
解决原始问题的方法取决于原始HTML的静态程度
<p>
的<p>
的第二个到第四个总是在<span>
的内部,第一个和第五个总是在它们的外部
如果满足这两个条件,你可以使用这样的东西:
var paragraphs = document.getElementsByTagName('p');
var newParagraphs = [];
function createElementWithText(tagname, text, classname) {
var classname = classname || '';
var element = document.createElement(tagname);
element.className = classname;
element.appendChild(document.createTextNode(text));
return element;
}
newParagraphs[0] = createElementWithText('p', paragraphs[0].textContent);
newParagraphs[0].appendChild(createElementWithText('span', paragraphs[1].textContent, 'myclass mytext'));
newParagraphs[1] = createElementWithText('p', paragraphs[2].textContent, 'myclass mytext');
newParagraphs[2] = document.createElement('p');
newParagraphs[2].appendChild(createElementWithText('span', paragraphs[3].textContent, 'myclass mytext'));
newParagraphs[2].appendChild(document.createTextNode(paragraphs[4].textContent));
我在JSFiddle上发布了一个工作示例:JSFiddle.net/vSrLJ/
您必须通过innerHTML
等获取源代码,操作字符串,然后输出字符串。
虽然DOM通常不会阻止<span>
中错误地包含<p>
这一事实,但它们在逻辑上不可能表示您想要的输出,因为没有HalfWrittenPElement
对象。
你故意违反规则的要求与为帮助你而设计的对象模型不一致,所以你只需要使用字符串进行黑客攻击。
编辑:
尽管如此,浏览器无论如何都会在其内部模型中修复它,所以它最终仍然会是格式良好的(如果不一定有效的话)HTML。根据实现定义的更正,而不是任何规范。
我还没有测试过,但你会明白的。您可以自己进行调试和跨浏览器微调;)
我会找到所有的<p>
标签,并为它们中的每一个检查其同级是否是<span>
、<span>
和<p>
。然后我将把<span>
s和第二个<p>
的文本放在第一个<p>
中。
var pTags = document.getElementsByTagName('p'); // get all <p>
for (var i = 0; i < pTags.length; i++) { // for every one of them
var a = pTags[i]; // take the <p> (and call it `a`)
var b = a.nextElementSibling(); // and the next tag (call it `b`)
if (b == null) continue;
var c = b.nextElementSibling(); // and the next tag (call it `c`)
if (c == null) continue;
var d = c.nextElementSibling(); // and the next tag (call it `d`)
if (d == null) continue;
if (b.tagName.toUpperCase() == 'SPAN' && // if b is <span>
c.tagName.toUpperCase() == 'SPAN' && // and c is <span>
d.tagName.toUpperCase() == 'P') { // and d is <p> again
a.appendChild(b); // put b inside a
a.appendChild(c); // put c inside a
a.appendChild(d.firstChild.nodeValue); // put text of d inside a
}
}
请注意,nextElementSibling
方法不是跨浏览器的,但您可以通过调用nextSibling
来模拟它,直到它是Element
类型。
还要注意,通过调用appendChild
,元素首先从其原始容器中移除,然后才被附加。这就是我们想要的。
快速编辑:
正如其他人所指出的,你有无效的html,这是我一开始没有注意到的。但我想你想让<span>
正确关闭。
- 如何从ajax返回两个html内容
- 使用Javascript匹配两个HTML元素的高度
- 我怎么能"合并”;两个HTML标签
- 使用jquery可交换地更改两个html输入表单值
- 确定两个HTML元素在没有ID的情况下是否不同
- 如何将两个 html 元素绑定在一起,当第一个元素被删除时,第二个元素也从 DOM 中删除
- 两个 html 对象(列表、输入)应该生成第三个列表
- 如何使用jQuery将两个html包含在另一个html中
- 一次提交两个 HTML 表单,一个在当前窗口中,一个在新窗口中
- 在两个 HTML 注释行之间插入内容
- 如何删除两个 Html 选择列表之间的重复项
- 交换两个 html 元素并保留其上的事件侦听器
- 冲突两个 HTML 表单
- 有没有办法将两个HTML ID链接到一个javascript函数
- 比较两个 HTML 源并显示视觉差异
- 在两个 html 文件之间更改 jQuery Mobile 的页面
- 仅使用客户端在两个 HTML 页面之间传递大量数据
- 两个 HTML Onsumbit 验证与 Java 一起
- 在两个HTML页面之间传递JavaScript变量
- 组合两个HTML文件