2

I want to provide a visual to show users how many of the characters remain in a textarea as they type in their response. My code below WORKS! but I kinda pieced the logic together and have A LOT of repetition. Is there a better way to write the jquery below that is more maintainable and succinct?

HTML

<td colspan="4" style="text-align:center;">
     NOTES<br>
     <textarea class="sam_notes maxed" maxlength="750" name="sam_notes" style="height:100px;width:90%;margin:0 auto;"></textarea>
     <br>
     <span style="font:normal 11px sans-serif;color:#B00400;">
         <span class='counter_msg'></span>
     </span>
</td>

JQUERY

(function() {
     $(document).on('focus', '.sam_notes', function(e){
      var msgSpan = $(this).parents('td').find('.counter_msg');
      var ml     = parseInt( $(this).attr('maxlength') );
      var length = $(this).val().length;
      var msg = ml - length + ' characters of ' + ml + ' characters left';

      msgSpan.empty().html(msg);
    });

    $(document).on('keyup', '.sam_notes', function(e){
      var msgSpan = $(this).parents('td').find('.counter_msg');
      var ml     = parseInt( $(this).attr('maxlength') );
      var length = $(this).val().length;
      var msg = ml - length + ' characters of ' + ml + ' characters left';

      msgSpan.empty().html(msg);
    });
})();
4

3 回答 3

6

这是一种方法:

$('td').on('focus keypress', '.sam_notes', function (e) {

    var $this = $(this);
    var msgSpan = $this.parents('td').find('.counter_msg');
    var ml = parseInt($this.attr('maxlength'), 10);
    var length = this.value.length;
    var msg = ml - length + ' characters of ' + ml + ' characters left';

    msgSpan.html(msg);
});

这是一个演示:http: //jsfiddle.net/hungerpain/8gKs4/2/

这是我按行顺序更改的内容:

  1. 删除document并将其更改为td. 这样事件就不会冒泡到父母身上。
  2. 改为。keyup_ 如果您的用户没有从键盘上移开手指,则不会工作。捕获和.keypresskeyupkeypresskeyupkeydown
  3. 既然你在focusand有同样的东西keypress,为什么不加入他们呢?
  4. 您使用$(this)了两次,因此将其缓存以备后用。(我知道..我知道..我在吹毛求疵)
  5. 添加了一个基数parseInt,这是一个 JSLINT 规则。基数是您添加到的额外数字parseInt查看此答案以获取更多信息。
  6. 改为$(this).val()this.value更原生。
  7. 删除empty()。由于您已经在使用html(),因此不需要。

希望这可以帮助!

于 2013-07-24T16:07:10.670 回答
3

我相信您还可以进行其他改进,但对我来说最明显的是:

重构更新计数逻辑以防止重复

(function() {
     $(document).on('focus', '.sam_notes', function(e){
      UpdateCount($(this));
    });

    $(document).on('keyup', '.sam_notes', function(e){
      UpdateCount($(this));
    });

    function UpdateCount(notes) {
      var msgSpan = notes.parents('td').find('.counter_msg');
      var ml     = parseInt( notes.attr('maxlength') );
      var length = notes.val().length;
      var msg = ml - length + ' characters of ' + ml + ' characters left';

      msgSpan.html(msg);
    }
})();

此外,您不需要在 html() 之前为 empty()

msgSpan.empty().html(msg);是相同的msgSpan.html(msg);

于 2013-07-24T15:57:32.183 回答
1

我看了一下: http ://www.scriptiny.com/2012/09/jquery-input-textarea-limiter/ 然后将其扩展为 jquery 小部件。
是的,我知道它完全被过度设计了。我只是为了了解有关小部件的更多信息。但从好的方面来说,它使用起来超级简单。只需调用文本区域上的小部件:

$(selector).limiter();

有一堆参数,您可以通过选项作为对象发送,例如;

 $(selector).limiter({maxChars:1000,warningChars:990});

请注意,您可以在 CSS 中添加类样式。我假设您在这里安装了 jqueryui css 以使警告文本在其warningChars 值时更改颜色。像 .ui-limiter-chars {position: absolute;padding-left: 1em;} 这样的东西可以解决问题......

看看小提琴... http://jsfiddle.net/DE5m9/2/

$.widget("ui.limiter", {
    options:{
        limiterClass:'ui-limiter-chars ui-widget-content',
        limiterTag:'small',
        maxChars:100,
        warningClass:'ui-state-error-text',
        warningChars:90,
        wrapperClass:'ui-limiter-wrapper ui-widget',
        tagName:'TEXTAREA'
    },
    _create: function(){
        // make sure that the widget can only be called once and it is only called on textareas
        var o = this.options;
        if (($(this).attr('aria-owns') === undefined ) && (this.element[0].tagName === o.tagName)) {
            var self = this;
            var id = Math.random().toString(16).slice(2, 10).replace(/(:|\.)/g, '');
            // ids = array of id of textarea, wrapper, and limiter chars ids.
            this.ids = [(this.element.attr('id') || 'ui-limiter-' + id),'ui-limiter-wrapper-'+id,'ui-limiter-chars-'+id];
            this.element[0].id = this.ids[0];
            var limiterWrapper = $('<div/>',{
                'class':o.wrapperClass,
                'id':this.ids[1]
            });
            // semantically, this seems to be a good fit for a small tag. ie not important.
            var limiterChars = $('<'+o.limiterTag+'/>', {
                'class': o.limiterClass,
                'id': this.ids[2]
            });

            $('#'+this.ids[0]).wrap(limiterWrapper);
            $('#'+this.ids[0]).after(limiterChars);
            $('#'+this.ids[0]).attr('aria-owns',this.ids[2]);
            $('#'+this.ids[0]).on("keyup focus", function() {
                self._setCount($('#'+self.ids[0]), $('#'+self.ids[2]));
            });
            this._setCount($('#'+this.ids[0]), $('#'+this.ids[2]));
        }
    },
    _setCount:function (src, elem) {
        var o = this.options;
        var chars = src.val().length;
        if (chars > o.maxChars) {
            src.val(src.val().substr(0, o.maxChars));
            chars = o.maxChars;
        }
        $('#'+this.ids[2]).text(o.maxChars - chars );
        if (chars > o.warningChars)
        {
            $('#'+this.ids[2]).addClass(o.warningClass);
        }
        else
        {
            $('#'+this.ids[2]).removeClass(o.warningClass);
        }
    },
    destroy: function(){
        $('#'+this.ids[2]).remove();
        $('#'+this.ids[0]).unwrap();
        $('#'+this.ids[0]).removeAttr('aria-owns');
        $.Widget.prototype.destroy.call(this);
    },

});
于 2013-10-08T11:35:46.627 回答