这是我的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&amp; 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>
答案 0 :(得分:1)
你必须通过innerHTML
等获取源代码,操纵字符串然后输出字符串。
虽然DOM通常不会阻止您在<p>
内错误地拥有<span>
这一事实,但它们在逻辑上不可能代表您想要的输出,因为没有{{1}对象。
您故意违反规则的要求与旨在帮助您的对象模型不一致,因此您可以使用字符串进行黑客操作。
编辑:
尽管如此,浏览器无论如何都将在内部模型中修复它,因此它仍将最终形成格式良好(如果不一定有效)的HTML。它只是根据实现定义的更正而不是任何规范。
答案 1 :(得分:1)
我没有对此进行过测试,但你会明白这一点。您可以自己进行调试和交叉浏览器微调;)
我会找到所有<p>
标签,并为每个标签检查其兄弟姐妹是<span>
,<span>
还是<p>
。然后我会将<span>
和第二个<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>
正确关闭。
答案 2 :(得分:1)
(跟我说吧,我在你最近的编辑之前开始写这个。我认为它仍然有用。)
我不确定你想要实现什么,但我可以告诉你,非常难以实现 你要求使用JavaScript的东西。这主要是因为HTML无效。
让我们首先介绍为什么 HTML无效。当浏览器解析HTML时,它会构建一个嵌套的树的DOM节点。你的第一个例子可以这样表示:
<p>
<span id="myid">
<span id="mytext">
<p>
<p>
<p>
<p>
使用JavaScript和DOM,您可以浏览此树并对其进行操作。您可以合并来自各种<p>
标记的文本节点,并将它们放在单个<p>
标记中而不会出现问题。但是你将无法创建第二个例子的结构。它的形状不像DOM树,因此您无法使用DOM来创建HTML。
将HTML操纵为第二个示例形状的唯一方法是innerHTML
,如Jon Hanna explains。好消息是,浏览器始终将无效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/