Javascript 限制 ContentEditable div 中的字符数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2867479/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 02:16:23  来源:igfitidea点击:

Limiting Number of Characters in a ContentEditable div

javascriptjquerycontenteditable

提问by Bill Dami

I am using contenteditable div elements in my web application and I am trying to come up with a solution to limit the amount of characters allowed in the area, and once the limit is hit, attempting to enter characters simply does nothing. This is what I have so far:

我在我的 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));
    }
}

This DOES limit the number of characters to the number specified by 'max', however once the area's text is set by the jquery .text() function the cursor resets itself to the beginning of the area. So if the user keeps on typing, the newly entered characters will be inserted at the beginning of the text and the last character of the text will be removed. So really, I just need some way to keep the cursor at the end of the contenteditable area's text.

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

回答by user113716

How about passing in the eventobject to your function and calling e.preventDefault()if the max is reached?

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();
    }
}

Although, you may need to do a little more to allow the user to do things like 'delete'.

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



EDIT:

编辑:

Added support for 'delete' key.

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



EDIT 2:

编辑2:

Also, you could probably get rid of the keyuphandler. keydownshould be enough.

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

回答by Bala Velayutham

A simple way to achieve this :

实现此目的的简单方法:

<div onkeypress="return (this.innerText.length <= 256)" contenteditable="true">

回答by Tim Down

Firstly, this kind of thing is irritating for the user: I would suggest instead doing something similar to StackOverflow's comment field, which allows you type as much or as little as you like, shows you a message telling you how many characters you've typed and whether it's too many or too few, and refuses to let you submit a comment whose length is not valid.

首先,这种事情对用户来说是令人恼火的:我建议改为做一些类似于 StackOverflow 的评论字段的事情,它允许您输入任意多或少的内容,显示一条消息告诉您您输入了多少个字符不管是多还是少,不让你提交长度无效的评论。

Secondly, if you really have to limit the length of text, replacing the whole content of the <div>on every keystroke if the content is too long is unnecessarily expensive, and will make the editor unresponsive on slower machines. I suggest handling the keypressevent and simply preventing the character being inserted using preventDefault()on the event (or in IE, setting the event's returnValueto true, assuming you're using attachEvent). This won't prevent the user from pasting text in, so you'll need to handle the pasteevent (which doesn't exist in Opera or Firefox < 3, so you'll need some kind of polling-based solution for those). Since you won't be able to access the content being pasted in advance, you'll have no way of knowing if the paste will take you over the character limit, so you'll need to set a timer to check the length again shortly after the paste. All that being the case, the first option seems preferable to me.

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

回答by VizardCrawler

This is the best way to do this most generalize form and just work great for me!

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

<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;
        }
    });

回答by Tschallacka

This is the way I did it by jQuery binding, making it easy for me by just adding a property data-input-length to a content editable element. Just add the javascript code anywhere in your document.

这是我通过 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>

回答by Vito Gentile

The following solution also considers the control keys (which correspond to non-printable characters).

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

//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; 
    }
});

回答by vodnycheck

Another version of the answer of @user113716. Supports "paste" event, and some text hotkeys like CTRL + A.

@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();
    }

回答by Yuval Perelman

$("[contenteditable=true]").keydown(function(e) {
    var max = $(this).attr("maxlength");
    if (e.which != 8 && $(this).text().length > max) {
        e.preventDefault();
    }
});

回答by Al Serize

If you would like to make it work with classes. In other words, element would be able to share class names and still have their own unique count:

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

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();
    }
}

回答by shawndumas

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);
};