48

我在我的 Web 应用程序中使用 contenteditable div 元素,我试图想出一个解决方案来限制该区域中允许的字符数量,一旦达到限制,尝试输入字符就什么也不做。这是我到目前为止所拥有的:

var content_id = 'editable_div';

//binding keyup/down events on the contenteditable div
$('#'+content_id).keyup(function(){ check_charcount(content_id, max); });
$('#'+content_id).keydown(function(){ check_charcount(content_id, max); });

function check_charcount(content_id, max)
{   
    if($('#'+content_id).text().length > max)
    {
        $('#'+content_id).text($('#'+content_id).text().substring(0, max));
    }
}

这确实将字符数限制为“max”指定的数量,但是一旦 jquery .text() 函数设置了区域的文本,光标就会将自身重置到区域的开头。因此,如果用户继续输入,新输入的字符将被插入到文本的开头,而文本的最后一个字符将被删除。所以真的,我只需要一些方法将光标保持在 contenteditable 区域文本的末尾。

4

13 回答 13

54

event对象传递给您的函数并e.preventDefault()在达到最大值时调用如何?

var content_id = 'editable_div';  

max = 10;

//binding keyup/down events on the contenteditable div
$('#'+content_id).keyup(function(e){ check_charcount(content_id, max, e); });
$('#'+content_id).keydown(function(e){ check_charcount(content_id, max, e); });

function check_charcount(content_id, max, e)
{   
    if(e.which != 8 && $('#'+content_id).text().length > max)
    {
       // $('#'+content_id).text($('#'+content_id).text().substring(0, max));
       e.preventDefault();
    }
}

虽然,您可能需要做更多的事情来允许用户执行“删除”之类的操作。


编辑:

添加了对“删除”键的支持。


编辑2:

此外,您可能会摆脱keyup处理程序。keydown应该足够了。

于 2010-05-19T16:37:01.947 回答
27

实现此目的的简单方法:

<div onkeypress="return (this.innerText.length <= 256)" contenteditable="true">
于 2013-09-10T17:50:51.650 回答
20

首先,这种事情对用户来说很烦人:我建议改为做一些类似于 StackOverflow 的评论字段的事情,它允许您输入任意数量或尽可能少的内容,显示一条消息,告诉您您输入了多少个字符以及是否太多或太少,并且拒绝让您提交长度无效的评论。

其次,如果你真的必须限制文本的长度,如果内容太长,每次击键都替换整个内容<div>是不必要的昂贵,并且会使编辑器在较慢的机器上无响应。我建议处理该keypress事件并简单地防止在preventDefault()事件上使用插入的字符(或在 IE 中,将事件设置returnValuetrue,假设您正在使用attachEvent)。这不会阻止用户粘贴文本,因此您需要处理paste事件(在 Opera 或 Firefox < 3 中不存在,因此您需要某种基于轮询的解决方案)。由于您将无法提前访问正在粘贴的内容,因此您无法知道粘贴是否会超过字符数限制,因此您需要设置一个计时器以便稍后再次检查长度粘贴后。既然如此,第一个选项对我来说似乎更可取。

于 2010-05-19T16:47:31.703 回答
5

这是我通过 jQuery 绑定实现的方式,只需将属性 data-input-length 添加到内容可编辑元素即可轻松实现。只需在文档中的任何位置添加 javascript 代码即可。

$(document).ready(function(){
	// Excempt keys(arrows, del, backspace, home, end);
	var excempt = [37,38,39,40,46,8,36,35];
	// Loop through every editiable thing
	$("[contenteditable='true']").each(function(index,elem) {
	    var $elem = $(elem);
	    // Check for a property called data-input-length="value" (<div contenteditiable="true" data-input-length="100">)
	    var length = $elem.data('input-length');
	    // Validation of value
	    if(!isNaN(length)) {
	    	// Register keydown handler
	        $elem.on('keydown',function(evt){
	        	// If the key isn't excempt AND the text is longer than length stop the action.
	            if(excempt.indexOf(evt.which) === -1 && $elem.text().length > length) {
	               evt.preventDefault();
	               return false;
	            }
	        });
	    }
	});
});
div {
  background-color:#eee;
  border: 1px solid black;
  margin:5px;
  width:300px;
  height:100px;
  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true" data-input-length="100">
You can type a 100 characters here
</div>
<div contenteditable="true" data-input-length="150">
You can type a 150 characters here
</div>
<div contenteditable="true" data-input-length="10">
You can type a 10 characters here
</div>

于 2015-11-16T08:22:55.897 回答
5

这是完成这种最概括形式的最佳方法,对我来说非常有用!

<div contenteditable="true" name="choice1" class="textfield" max="255"></div>
    $('.textfield').on("keypress paste", function (e) {
        if (this.innerHTML.length >= this.getAttribute("max")) {
            e.preventDefault();
            return false;
        }
    });
于 2015-07-27T07:11:17.937 回答
4

以下解决方案还考虑了控制键(对应于不可打印的字符)。

//Maximum number of characters
var max = 200;

$('#editable_div').keydown(function(e) {
    var keycode = e.keyCode;

    //List of keycodes of printable characters from:
    //http://stackoverflow.com/questions/12467240/determine-if-javascript-e-keycode-is-a-printable-non-control-character
    var printable = 
        (keycode > 47 && keycode < 58)   || // number keys
        keycode == 32 || keycode == 13   || // spacebar & return key(s) (if you want to allow carriage returns)
        (keycode > 64 && keycode < 91)   || // letter keys
        (keycode > 95 && keycode < 112)  || // numpad keys
        (keycode > 185 && keycode < 193) || // ;=,-./` (in order)
        (keycode > 218 && keycode < 223);   // [\]' (in order)

    if (printable) {
        //Based on the Bala Velayutham's answer
        return $(this).text().length <= max; 
    }
});
于 2014-08-19T10:57:53.243 回答
4

@user113716 答案的另一个版本。支持“粘贴”事件,以及一些文本热键,如 CTRL + A。

$('#'+content_id).on('keydown paste', function (e) { maxLimitForContenteditableDiv(e, 140) });

function maxLimitForContenteditableDiv(e, limit) {
    var allowedKeys = false;

    if (e.type === 'keydown') {
        allowedKeys = (
            e.which === 8 ||  /* BACKSPACE */
            e.which === 35 || /* END */
            e.which === 36 || /* HOME */
            e.which === 37 || /* LEFT */
            e.which === 38 || /* UP */
            e.which === 39 || /* RIGHT*/
            e.which === 40 || /* DOWN */
            e.which === 46 || /* DEL*/
            e.ctrlKey === true && e.which === 65 || /* CTRL + A */
            e.ctrlKey === true && e.which === 88 || /* CTRL + X */
            e.ctrlKey === true && e.which === 67 || /* CTRL + C */
            e.ctrlKey === true && e.which === 86 || /* CTRL + V */
            e.ctrlKey === true && e.which === 90    /* CTRL + Z */
        )
    }

    if (e.type === 'paste') {
        setTimeout(function () {
            $(e.target).text($(e.target).text().slice(0, limit));
        });
    }

    if (!allowedKeys && $(e.target).text().length >= limit) {
        e.preventDefault();
    }

于 2019-03-21T06:13:15.007 回答
1
$("[contenteditable=true]").keydown(function(e) {
    var max = $(this).attr("maxlength");
    if (e.which != 8 && $(this).text().length > max) {
        e.preventDefault();
    }
});
于 2015-07-01T10:44:12.330 回答
0

这是@user113716 答案的更通用版本,因为当多个 contenteditable 字段正在使用目标类时,它无法正常工作。他们的答案计算了与给定类匹配的所有元素的总字符数,因此您只能在页面上输入 max characters total

此解决方案允许您使用通用类,并独立限制每个 contenteditable 字段中的字符数。

的HTML:

<div contenteditable="true" name="choice1" class="textfield"></div>

和 JavaScript:

MAX_TEXTINPUT = 10;
TEXTFIELD_CLASS = "textfield"

$(document).ready(function() {

    //binding keyup/down events on the contenteditable div
    $('.'+TEXTFIELD_CLASS).keydown(function(e){ check_charcount(TEXTFIELD_CLASS, MAX_TEXTINPUT, e); });

})

function check_charcount(inputclass, max, e) {   
    var focused = $(document.activeElement)

    if(focused.hasClass(inputclass) && e.which != 8 && $(focused).text().length >= max)
    {
        e.preventDefault();
    }
}
于 2013-07-18T21:09:45.260 回答
0

如果你想让它与类一起工作。换句话说,元素将能够共享类名并且仍然拥有自己的唯一计数:

var content_id = '.myclass';  

max = 1;
//binding keyup/down events on the contenteditable div
$(content_id).keyup(function(e){ check_charcount(this, max, e); });
$(content_id).keydown(function(e){ check_charcount(this, max, e); });

function check_charcount(elem, max, e){   
    if(e.which != 8 && $(elem).text().length >= max){       
        e.preventDefault();
    }
}
于 2014-09-14T04:31:40.200 回答
0
var onKeyPress = function () {
    var keyCode = window.event.keyCode,
        isNumeric = (keyCode > 47 && keyCode < 58),
        isNotEnterKey = !!(window.event.keyCode !== 13);

        (isNotEnterKey) || (this.blur());

        return (isNumeric && this.innerText.length < 3);
};
于 2010-08-02T16:47:47.293 回答
0

上述解决方案并未涵盖所有情况!如果您想更正确地限制字符数,可以使用我的轻量级库 - https://github.com/antpv/contenteditable-max-length/tree/master

于 2020-12-03T21:11:25.983 回答
0
<div id="test" contenteditable="true" tabIndex="-1"></div>
  <p><span id="sy">0</span>/120</p> 
var flag = true;
 $('#test').on('compositionstart', function() {
        flag = false;
    });
    $('#test').on('compositionend', function() {
        flag = true;
    });
    $('#test').on('input', function() {
      setTimeout(function() {
        if (flag) {
          if($('#test').text().length>= 120) {
            setTimeout(() => {
              $('#test').text($('#test').text().substring(0, 120));
              var range = window.getSelection(); //创建range
              range.selectAllChildren(document.getElementById('test')); //range 选择obj下所有子内容
              range.collapseToEnd();
              $("#sy").text($('#test').text().length)
            }, 0);
          } else {
            $("#sy").text($('#test').text().length)
          }

        }
      }, 0);
    });
于 2019-10-11T07:45:47.420 回答