Chrome在带有maxlength属性的文本区域中计算字符时出现错误

46

这里是一个示例:

$(function() {
  $('#test').change(function() {
    $('#length').html($('#test').val().length)
  })
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id=test maxlength=10></textarea>
length = <span id=length>0</span>

所以在我的情况下,在chrome停止之前,我只能输入7个字符(包括空格),尽管maxlength属性的值为10:

imgur


相似问题:https://dev59.com/fmnWa4cB1Zd3GeqP3K8k - styfle
OR或可能是这个:https://dev59.com/KGbWa4cB1Zd3GeqPcvwH - Tats_innit
10个回答

40

以下是如何使您的JavaScript代码与浏览器认为在文本区域中有多少个字符匹配的方法:

http://jsfiddle.net/FjXgA/53/

$(function () {
    $('#test').keyup(function () {
        var x = $('#test').val();

        var newLines = x.match(/(\r\n|\n|\r)/g);
        var addition = 0;
        if (newLines != null) {
            addition = newLines.length;
        }

        $('#length').html(x.length + addition);
    })
})

基本上,您只需计算文本框中的换行符总数,并为每个换行符的数量加1以得到字符计数。


7
也可以写成:$('#length').html(x.replace(/(\r\n|\n|\r)/g, '--').length); - noitseuq
3
这在Firefox中运作不正确,因为它将换行符视为一个字符。 - Stalinko
@Stalinko 我刚在Firefox、Chrome、IE、Edge和Opera中测试了一下,它们似乎都能正常工作。换行符会增加2个长度。你是指这个吗?还是有其他的意思? - nmit026
@Tim,尽管脚本正确显示了长度,但如果回车已经存在,它仍然允许输入更多字符。在我输入两个回车后,我可以继续输入12个字符。 - Nevin

33

当涉及到maxlength时,您的换行符被视为每个字符2个。

1\r\n
1\r\n
1\r\n
1

但似乎JavaScript只能处理一个\r\n(我不确定是哪一个),这只会增加到7


我已经在Chrome和Firefox上记录了这个问题的错误;在Chrome的最新版本中似乎已经修复了。 - Pointy
@Pointy 我正在使用 Chrome 的开发版本 (19.0.1084.1),但我仍然遇到了这个问题。 - Naftali
13
当文本框中的内容被实际提交时,其中嵌入的换行符必须以CR LF对的形式进行传输。因此,浏览器报告内容长度时应当按照每个换行符占用2个字符的方式计算。请注意,以上为直译,可能需要根据上下文进行调整。 - Pointy
2
@Neal 哦,我是根据原帖上的评论来判断的。这似乎是一个相当严重的问题,因为它使“maxlength”属性基本无用。 - Pointy
这是一个Angular表达式的修复方法:https://dev59.com/WYzda4cB1Zd3GeqPhQok#30875979 - Stephen Saucier
显示剩余2条评论

14
出于未知原因,jQuery总是将<textarea>的值中的所有换行符转换为单个字符。也就是说,如果浏览器使用\r\n表示换行符,jQuery会确保在.val()的返回值中只有\n

Chrome和Firefox都以相同的方式计算<textarea>标签的长度,用于“maxlength”。
然而,HTTP规范坚持要将换行符表示为\r\n。因此,jQuery、Webkit和Firefox都做错了。
总之,如果您的服务器端代码确实对字段值有固定的最大大小限制,那么在<textarea>标签上使用“maxlength”几乎没有什么用处。
编辑 - 在2014年末,看起来Chrome(38)表现正确。但是Firefox(33)仍然不会将每个硬回车计为2个字符。

好的 - 我会把这个复制到那里。 - Pointy
看起来你是在说.val()返回的是错误的(1个字符),但浏览器正确地将其视为2个字符,因此maxlength会考虑每个换行符的2个字符。如果是这种情况,并且您的后端数据库有一个固定的最大值,我不明白为什么maxlength是无用的,因为它正确地计算了将保存在数据库中的字符数。 - wired_in
2
@wired_in 再次你好 :) 问题在于内置的 maxlength 检查不考虑 CR 字符。这意味着内置的 maxlength 允许文本区域在客户端中包含比允许的实际字符更多的字符。因此,如果您有一个长度为500个字符的数据库字段,并且您说 maxlength=500,则发布的表单可能包含一个值,其中超过500个字符。因此,该属性是无用的。 - Pointy
点赞关于textarea字段的maxlength属性是无用的信息。 - Baz Guvenkaya
显示剩余6条评论

14

根据上面Pointy的回答,正确的方法似乎是将所有换行符视为两个字符进行计数。这将标准化各种浏览器并匹配发布时发送的内容。

因此,我们可以遵循规范,将所有Carriage Return(回车)后面没有New Line(换行)的出现,以及所有New Line没有Carriage Return的出现,都替换为一个Carriage Return - Line Feed(回车换行)对。

var len = $('#test').val().replace(/\r(?!\n)|\n(?!\r)/g, "\r\n").length;

然后使用该变量来显示文本区值的长度,或进行限制等操作。


3
看起来 JavaScript 也会考虑换行符的长度。
尝试使用以下代码:

var x = $('#test').val();

x = x.replace(/(\r\n|\n|\r)/g,"");    

$('#length').html(x.length);


我在你的fiddle里使用它,它是有效的。希望这有所帮助。

1
如果您想获取文本区域的剩余内容长度,那么可以在包含换行符的字符串上使用匹配操作。
HTML:
<textarea id="content" rows="5" cols="15" maxlength="250"></textarea>

JS:

var getContentWidthWithNextLine = function(){
    return 250 - content.length + (content.match(/\n/g)||[]).length;
}

1

这是因为一个新行实际上是2个字节,因此长度为2。但JavaScript并不这样看待它,因此它只会计算1次,使总数为7(3个新行)。


1
这里提供了一种更通用的解决方案,它覆盖了jQuery的“val”函数。很快会将此问题转化为博客文章并在此处链接。
var originalVal = $.fn.val;
$.fn.val = function (value) {
    if (typeof value == 'undefined') {
        // Getter

        if ($(this).is("textarea")) {
            return originalVal.call(this)
                .replace(/\r\n/g, '\n')     // reduce all \r\n to \n
                .replace(/\r/g, '\n')       // reduce all \r to \n (we shouldn't really need this line. this is for paranoia!)
                .replace(/\n/g, '\r\n');    // expand all \n to \r\n

            // this two-step approach allows us to not accidentally catch a perfect \r\n
            //   and turn it into a \r\r\n, which wouldn't help anything.
        }

        return originalVal.call(this);
    }
    else {
        // Setter
        return originalVal.call(this, value);
    }
};

1
顺便说一下,这篇博客文章很棒。 - Kristopher

0
var value = $('#textarea').val();
var numberOfLineBreaks = (value.match(/\n/g)||[]).length;
$('#textarea').attr("maxlength",500+numberOfLineBreaks);

在谷歌上已经完美运行,但在IE中必须避免脚本!在IE中,“断行”只计算一次,因此请避免使用此解决方案!


粘贴时会失败。 - user663031

0

文本区域在各个浏览器之间仍然没有完全同步。我注意到了两个主要问题:回车符和字符编码。

回车符

默认情况下被处理为 2 个字符\r\n(Windows 样式)。

问题在于 Chrome 和 Firefox 将其计为一个字符。你也可以选择它来观察,会发现一个不可见的字符被选中作为空格。

这里有一个解决方法:

var length = $.trim($(this).val()).split(" ").join("").split('\n').join('').length;

当用户输入换行时,Jquery单词计数

而另一方面,Internet Explorer会将其视为2个字符。

它们的表示形式是:

二进制:00001101 00001010

十六进制:0D0A

在UTF-8中表示为2个字符,并且在maxlength中计算为2个字符。

HTML实体可以通过以下方式创建:

1)从JavaScript代码创建:

<textarea id='txa'></textarea>

document.getElementById("txa").value = String.fromCharCode(13, 10);

2)从文本区域的内容解析:

Ansi代码:&#13;&#10;

<textarea>Line one.&#13;&#10;Line two.</textarea>

3) 从键盘插入回车键

4) 定义为文本框的多行内容

<textarea>Line one.
Line two.</textarea>

字符编码

输入字段(如文本区域)的字符编码与页面的字符编码是独立的。如果您计划计算字节数,则这一点非常重要。因此,如果您有一个元标头来定义页面的ANSI编码(每个字符1个字节),则文本框的内容仍然是UTF-8编码,每个字符占用2个字节。

这里提供了一个字符编码的解决方法:

function htmlEncode(value){
  // Create a in-memory div, set its inner text (which jQuery automatically encodes)
  // Then grab the encoded contents back out. The div never exists on the page.
  return $('<div/>').text(value).html();
}

function htmlDecode(value){
  return $('<div/>').html(value).text();
}

从输入字段读取属性时丢失HTML编码


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