用一个 <br> 替换多个 <br>

52

我如何使用JavaScript检测

<br>
<br>
<br>

成为一体

<br>

我尝试了:

jQuery('body').html().replace(/(\<br\>\r\n){3, }/g,"\n");

但是对我来说这并不起作用。


2
我很惊讶没有人建议使用正则表达式 :( - Lescai Ionel
6
@LescaiIonel 确实吗?请看回答。但是我们已经有了DOM,为什么还要麻烦正则表达式呢?(有一天我们会看到Tony the pony)。此外,替换HTML将导致浏览器重新解析HTML,这是不高效的。 - Alvin Wong
5
如果你不希望有多个 <br>,那么为什么一开始就加了它们呢? - RoToRa
2
这个问题和答案是如何在短时间内获得如此多的浏览量和投票数的呢? - Rob W
3
更加有趣的是,这个问题首先是如何进入热门问题的。 - BoltClock
显示剩余4条评论
9个回答

172

CSS解决方案

如果你想在页面上禁用多个<br>的效果,你可以通过CSS而不使用JavaScript来实现:

br + br { display: none; }

然而,当您使用标签时,这种方法是理想的,就像这样:

<div>Text</div><br /><br /><br />
<div>Text</div><br /><br /><br />
<div>Text</div><br /><br /><br />

在其他情况下,比如这种情况:
Hello World<br />   <br />
Hello World<br />   <br />
Hello World<br />   <br />

它将失败(因为 CSS 会通过文本节点)。相反,请使用 JavaScript 解决方案。


JavaScript 解决方案

// It's better to wait for document ready instead of window.onload().
window.onload = function () {
    // Get all `br` tags, defined needed variables
    var br = document.getElementsByTagName('br'),
        l = br.length,
        i = 0,
        nextelem, elemname, include;
        
    // Loop through tags
    for (i; i < l - 1; i++) {
        // This flag indentify we should hide the next element or not
        include = false;
        
        // Getting next element
        nextelem = br[i].nextSibling;
        
        // Getting element name
        elemname = nextelem.nodeName.toLowerCase();
        
        // If element name is `br`, set the flag as true.
        if (elemname == 'br') {
            include = true;
        }
        
        // If element name is `#text`, we face text node
        else if (elemname == '#text') {
            // If text node is only white space, we must pass it.
            // This is because of something like this: `<br />   <br />`
            if (! nextelem.data.replace(/\s+/g, '').length) {
                nextelem = br[i+1];
                include = true;
            }
        }
        
        // If the element is flagged as true, hide it
        if (include) {
            nextelem.style.display = 'none';
        }
    }
};

23
“br + br”的定义是指一个紧接在另一个“br”元素后面的“br”元素。它只匹配一个元素,而不是同时匹配两个。该选择器将匹配除第一个外的所有连续“br”元素。 - MatsT
14
这个解决方案可以删除比预期更多的<br>,如果它们之间没有标签的话:http://jsfiddle.net/ahMMv/13/ - zch
2
这些新奇的东西是什么?自从我刚开始学习编程以来,事情已经发生了变化。 - David G
2
@0x499602D2 你是指CSS中的+符号吗?它已经成为标准一段时间了,就像>符号一样。 - jackweirdy
3
这是@zch发现问题的解决方案:http://jsfiddle.net/ahMMv/17/。 - Passerby
显示剩余2条评论

10

发送不需要的HTML代码到客户端浏览器并让它运行JavaScript清理它的目的是什么?这看起来像是一个糟糕的设计。

为什么不修复所有静态HTML和HTML生成,以便这些多余的<br>元素在第一次出现时就不会出现呢?

如果您使用JavaScript修改文档对象,请这样做以获得无法通过其他方式实现的动态效果。


2
也许这些多个 <br> 标签已经是由 Javascript 创建的。 - Uooo
6
也许这个 HTML 是从另一个网站获取的。Javascript 并不总是与特定网站捆绑的。浏览器中可能会有作为浏览器扩展运行的 Javascript,用于编辑用户的 HTML。 - Kaz
2
虽然总的来说你的建议是好的(所以+1),但它并没有直接回答问题。有时候你必须处理HTML,而你完全无法控制谁生成它或为什么以那种方式生成 - 在这种情况下,对于像这样的问题直接解决方案变得有益,而像“从一开始就修复它”这样的事情则变得不可能。(另一方面,通常这些你无法控制的HTML转换都发生在服务器端,因此它们可以在那一侧进行修复 - 无论如何,在JavaScript中进行这种操作可能是错误的地方)。 - Ben Lee
1
但是,我仍然可以看到在控件之外进行客户端HTML操作仍然存在有效的理由 - 只是不太典型。 - Ben Lee
1
哇,没有上下文知识,也没有答案,却还要说“这是糟糕的设计”。 - Dalibor Čarapić
@dcarpic 我说它看起来像是一个糟糕的设计,而不是它本身就是一个糟糕的设计。情境可能是这样的,它并不是一个好的设计。其他答案已经多次涵盖了“如何”,但同样缺乏对情境的了解。 - Kaz

9

简化版:

var newText = oldText.replace(/(<br\s*\/?>){3,}/gi, '<br>');

这将允许可选的标签终止符(/>)以及标签结束前的空格(例如<br /><br >)。


但是我该如何确保它只在找到3个以上的<br>时才起作用呢? - user610983
它将任何2个或更多的内容替换为1个。 - marekful
但如果我像这样专注于某个元素ID: jQuery('#content')。html()。replace(/(<br\s*/?>){3,}/gi,'<br>'); ??应该没有问题吧?但它仍然对我无效。 - user610983
好的,考虑一下:text = 'abc def'; text.replace('def', 'ghi'); text 现在没有改变!但是 text = text.replace('def', 'ghi'); 现在 text 已经被改变了。 - marekful
1
仅仅执行.replace()方法并不会改变原始值。你必须将replace方法的返回值赋值给原始变量。 - marekful
显示剩余3条评论

2
这个解决方案是仅基于jQuery和DOM,不涉及HTML字符串操作,适用于文本节点,会忽略仅包含空格的文本节点:
$('br').each(function () {
  const {nodeName} = this;

  let node = this;

  while (node = node.previousSibling) {
    if (node.nodeType !== Node.TEXT_NODE || node.nodeValue.trim() !== '') {
      break;
    };
  }

  if (node && node !== this && node.nodeName === nodeName) {
    $(node).remove();
  }
});

参见:https://jsfiddle.net/kov35jct/


我不明白以下这行代码的作用: while (node = node.previousSibling) { if (node.nodeType !== Node.TEXT_NODE || node.nodeValue.trim() !== '') { break; }; } - Simon

1

这样的做法是否正确:

$("br~br").remove()

编辑:不,这是错误的,因为它对“连续”的定义太宽松了,正如BoltClock所说。


1
具体来说,这是jQuery的“下一个兄弟元素”选择器: http://api.jquery.com/next-siblings-selector/ - mskfisher
14
尽管<br>元素不是连续的,但这会删除<br><hr><br><hr>中的第二个<br>。根据使用情况,可能并不希望这样做。 - BoltClock
2
你太客气了。谢谢 :) - Steve Bennett
2
@BoltClock 应该使用相邻选择器,对吧? - Licson

0

试试这个

$('body').html($('body').html().replace(/(<br>)+/g,"<br>"));

它将把n个<br>替换为一个。

演示


3
如果在不同的<br>标签之间有任何东西,比如说一个空格或者一个换行符,那么这个解决方案就会破裂。 - Eivind Eidheim Elseth
1
将DOM转换为HTML,然后再转回去是一个不好的主意。 - lonesomeday
1
最佳的正则表达式应该是:.replace(/(<br\s*\/?>\s*)+/g, "<br>\n"),它可以处理各种间距和换行符。此外,替换后也会换行。我建议用<br />\n进行替换,但他似乎不喜欢自闭合标签。 - Suamere
@lonesomeday:你需要循环遍历每个元素,这应该比转换为HTML字符串形式、操作字符串,然后再将其转换回DOM形式要慢,尽管我不会放弃看到这种实现的机会! - Qantas 94 Heavy
2
@Qantas94Heavy 问题更多的是你会因此丢失信息。例如,绑定在 body 内部的任何事件处理程序都将被删除。在我看来,这不是一个好主意。 - lonesomeday

0
我会选择这个:
$('body').html($('body').html().replace(/<br\W?\\?>(\W?(<br\W?\\?>)+)+/g,"<br>"));

然而,在阅读了这里另一篇帖子中的评论后,我认为你应该尽量避免这样做,除非你可以在后端进行更正。


0
很多其他回答这个问题的方法只会替换某些数量的元素,或使用复杂的循环。我想出了一个简单的正则表达式,可以用来将 <br> 标签的 任何 数量替换为一个标签。这适用于字符串中多个标签的多个实例。
/(<br>*)+/g

要在JavaScript中实现这个功能,您可以使用 String.replace 方法:
myString.replace(/(<br>*)+/g, "<br/>");

如果要替换多个 <br/> 标签,请在正则表达式中添加 /

/(<br\/>*)+/g

-1

试试这个:

jQuery('body').html(
      jQuery('body').html().replace(/(?:<br>\s+){3,}/ig,"\n"));
);

演示: jsfiddle


不要扣她分!她提出的建议很好,只是将所有的<br>替换为换行符\n。将其更改为<br>,你就没问题了。 - yardarrat
这是一个不错的尝试,但使用正则表达式而不是DOM会保证未来出现问题和边缘情况。 - mskfisher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接