1

在我的表单中,我有一个 zend_form_element_textarea。对于这个元素,我添加了一个验证器 StringLength,如下所示:

$this->addElement('textarea', 'text', array('label' => 'F_MESSAGE_SMS_TEXT', 'required' => true, 'class' => 'fieldLiveLimit', 'limit' => 160));
$this->text->addValidator('StringLength', false, array('max' => 160));

我使用脚本 javascript 来显示实时倒计时字符:

//Text field or text area limit - get limit by field parameter
    $(".fieldLiveLimit").each(function () {
        var characters = $(this).attr('limit');
        var remaining = calcDifference(characters, $(this).val());
        if ($('.limitCounter').length > 0) {
            $(this).after($('.limitCounter').first().clone());
            $(this).next('.limitCounter').children('span').html(remaining);
        } else {
            $(this).after($("<div class='limitCounter'>" + translate('L_LIMIT_COUNTER', [remaining]) + "</div>"));
        }
        checkClassCounter(remaining, $(this));

        $(this).bind('textchange', function (event, previousText) {
            remaining = calcDifference(characters, $(this).val());
            checkClassCounter(remaining, $(this));
            if ($(this).val().length > characters) {
                $(this).val($(this).val().substr(0, characters));
            } else {
                $(this).next('.limitCounter').children('span').html(remaining);
            }
        });

        function calcDifference(characters, value) {
            return characters - parseInt(value.length);
        }

        function checkClassCounter(remaining, element) {
            if (parseInt(element.val().length) == 0) {
                element.next(".limitCounter").hide();
            } else {
                element.next(".limitCounter").show();
                if (remaining <= 10) {
                    element.next(".limitCounter").addClass('red-message');
                } else {
                    element.next(".limitCounter").removeClass('red-message');
                }
            }
        }
    });

这很好用,除了一件事。如果在文本区域内有新行,验证器将新行视为两个字符,而我的 JS 脚本为一个。谁错了?我觉得是zend验证器,不过好像真的是个奇怪的东西再问你!

4

1 回答 1

1

正如用户 Pankrates 在他的评论中已经指出的那样,这与换行符有关。

事实上,这个问题比最初看起来要复杂得多,因为它至少有两个维度:

  1. jQuery 去除函数中的回车符val()“目前,在 textarea 元素上使用 .val() 会从浏览器报告的值中去除回车符。” jQuery 文档
  2. 浏览器如何计算换行符是不一致\r\n的。有关 SO 的相关问题,请参见此处此处。但是,在我系统上安装的所有浏览器(Firefox 20.0 和 Chrome 26.0)上,\r\n都算作两个字符,所以我无法确认这一点。

请参阅此小代码片段以进行演示:

<?php
$str1 =  "test\nstring";
$str2 =  "test\r\nstring";
?>
    <textarea id="text1"><?php echo $str1 ?></textarea>jQuery: <span id="jquery1"></span>, JS: <span id="js1"></span>, PHP: <?php echo iconv_strlen($str1) ?>
    <textarea id="text2"><?php echo $str2 ?></textarea>jQuery: <span id="jquery2"></span>, JS: <span id="js2"></span>, PHP: <?php echo iconv_strlen($str2) ?>

<script type="text/javascript">
        $(document).ready(function() {
                $("#jquery1").text($("#text1").val().length);
                $("#js1").text("<?php echo str_replace(array("\n", "\r"), array('\n', '\r'), $str1) ?>".length);
                $("#jquery2").text($("#text2").val().length);
                $("#js2").text("<?php echo str_replace(array("\n", "\r"), array('\n', '\r'), $str2) ?>".length);
        });     
</script>

它给了我第一个盒子jQuery: 11, JS: 11, PHP: 11,但我得到了第二个盒子jQuery: 11, JS: 12, PHP: 12

我能想到几种解决方案(没有一个是理想的):

  1. Zend_Filter_PregReplace在您的表单中使用 a将所有内容\r\n替换为\n. 优点:计数将与 jQuery 的一致,val()并且相对容易。缺点:您正在破坏用户的换行符,这可能会导致不需要的结果。
  2. 装饰Zend_Validate_StringLength以便您可以在方法中替换\r\nby 。优点:将保留用户的换行符,缺点:您可能会得到一个超过 200 个字符的有效结果,因为被计为一个字符,您需要引入一个新类。\nisValid()\r\n
  3. 使用jQuery 的 textarea.valHooks将所有换行符替换为\r\n: Pro:简单,Con:如果您的用户具有\n换行符,它再次会给您带来不一致的结果。

我希望这个答案能根据您的应用程序的上下文向您展示如何解决这种情况的一些方向。

于 2013-04-13T10:51:58.863 回答