【问题标题】:Neatest (and fast) way to remove top lines from a textarea从文本区域中删除顶行的最简洁(也是快速)的方法
【发布时间】:2026-01-07 14:50:01
【问题描述】:

我有一个网页,它显示日志文件的最后1000 行,然后每隔x 秒通过AJAX 更新一次,加载新内​​容(如果有)并使用$('#log').append(new_data) 附加到textarea,一种tail -f

当附加的行过多并且页面变得缓慢或无响应时,问题会在一段时间后出现。

所以我想将行数限制为 5000,所以这意味着我应该:

  • 检索new_data
  • 计算overflow = 5000 - lines_ in_new_data - lines_in_textarea
  • 如果overflow > 0从textarea中删除第一行overflow
  • 将 new_data 附加到文本区域

在我看来,这涉及split('\n')textareanew_data 值中的一个或多个split('\n'),然后使用数组长度和切片,但我想是否有更简洁或更好的方法来实现这一点。

【问题讨论】:

  • Textareas 实际上并没有将'\n' 显示为换行符。文本区域是否可调整大小?如果限制为字符数而不是行数,会简单得多。
  • 赞成使用字符长度而不是行数。
  • 我知道这会简单得多,但我希望尽可能以 linuxish 基于行的方式使页面正常工作。毕竟这是一个日志......即使有一些解决方法可以很容易地避免这将是非常丑陋的第一行 textarea 被截断......
  • @Matt:不,它不能调整大小,只是一个纯文本区域 80cols x 24rows
  • 如果 textarea 限制为 80 列,那么当日志行包含超过 80 个字符时会发生什么情况?它是换行到下一行,还是溢出宽度?当你想删除多余的行时,你想把多余的字符算作一行的一部分吗?顺便说一句,某些浏览器将允许使用句柄调整任何文本区域的大小,除非您 explicitly disable it.

标签: javascript jquery textarea


【解决方案1】:

您应该能够在截断数据后使用单个 splitjoin,如下所示:

// on data retrieved
var total = ((textarea.value 
              ? textarea.value + "\n" 
              : "") 
          + new_data).split("\n");

if (total.length > 10) 
    total = total.slice(total.length - 10);

textarea.value = total.join("\n");

工作示例:http://jsfiddle.net/ArvQ7/(为简洁起见减少到 10 行)

【讨论】:

  • +1,我非常喜欢你使用时间戳的策略,这样可以很容易地看到滑动窗口。
  • 您可能需要将textarea.value = total.join("\n") 更改为textarea.val(total.join("\n")) 以使用jQuery 运行代码。
  • @neurino:是的,你可以,但我更喜欢直接映射到 DOM 属性而不是使用 jQuery 的访问器方法。它的效率稍微高一点 :-) 如果 textarea 是一个 jQuery 对象,它将是 textarea[0].value
  • @Andy:直接映射到 DOM 是否确保相同的跨浏览器兼容性?
【解决方案2】:

类似这样的东西(下面链接的演示可能更有用):

HTML

<button id="clickme">More lines</button>
<br/>
<textarea id="log" rows="24" cols="80"></textarea>
<p>Lines: <span id="numLines">0</span></p>

JavaScript

var $log = $('#log'),
    $button = $('#clickme'),
    $numLines = $('#numLines'),
    MAX_LINES = 5000,
    lorem_ipsum = ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
    lineCounter = 0;

$button.click(function()
{
    $log.val($log.val() + generateMoreLines()).change();
});

$log.change(function ()
{
    var text = tail(MAX_LINES, $log.val());
    $log.val(text);
    $numLines.text(countNewlines(text));
});

function generateMoreLines()
{
    var buf = [];
    for (var i = 0; i < 1000; i++)
    {
        buf.push(lineCounter++ + lorem_ipsum);
    }
    return buf.join('\n');
}

function countNewlines(haystack)
{
    return count('\n', haystack);
}

function count(needle, haystack)
{
    var num = 0,
        len = haystack.length;
    for (var i=0; i < len; i++)
    {
        if (haystack.charAt(i) === needle)
        {
             num++;
        }
    }
    return num;
}

function tail(limit, haystack)
{
    var lines = countNewlines(haystack) + 1;
    if (lines > limit)
    {
        return haystack
            .split('\n')
            .slice(-limit)
            .join('\n');
    }
    return haystack;
}

换行处理并不完美(您是否计算所有出现的'\n'?如果字符串以'\n' 开头或结尾怎么办?等等)。

演示:http://jsfiddle.net/mattball/3ghjm/

【讨论】:

  • 谢谢,添加新内容时只需要换行即可。由于内容来自日志文件字符串,因此开始和结束时总是没有\n(我第一次使用tail -n 1000 获取内容,然后记住文件位置并在后续调用中使用seek)。