文本区域变化检测


132

如何使用JavaScript在textarea上检测更改事件?
我正在尝试检测您输入的剩余字符数。

我尝试使用onchange事件,但这似乎仅在焦点移开时才起作用。

Answers:


97

您将需要使用onkeyup onchange。onchange将阻止上下文菜单粘贴,并且onkeyup将为每次击键触发。

请参阅我的有关如何对textArea施加maxlength的答案获取代码示例。


3
只是想强调Josh所说的,您应该使用keyup而不是keydown:keydown似乎是在对文本区域进行实际更改之前调用的,因此您使用的长度错误(并且您不会真的不知道您的状况如何:可能正在输入或删除,并且可能选择了文本,这意味着它不只是+/- 1)。
brianmearns 2012年

65
我在这里给-1,抱歉! onkeyup是输入检测的可怕事件。使用oninputonpropertychange(用于IE支持)。
Andy E

6
“唯一”的问题是onchange不是在上下文菜单剪切/粘贴时被解雇。
汤姆(Tom)

4
使用onkeydown和setTimeout响应更快,因此您可以立即检测到更改,而不必等待键被释放。如果还需要捕获剪切和粘贴,请使用剪切和粘贴事件。
凯文B

1
警告:onkeyup会给您带来麻烦。示例:假设您仅应在输入内容更改的情况下执行某些操作。如果您认为键盘输入会更改输入,则该输入不正确。将重点放在输入上。使用“标签”移动到下一个字段。现在使用“ shift + tab”返回到输入。触发键盘,但用户并未实际更改输入。
Zig Mandel

117

现在是2012年,即后PC时代到来了,我们仍然必须为像这样的基本问题而奋斗。这应该非常简单

在实现梦想之前,最好的方法是跨浏览器:使用inputonpropertychange事件的组合,如下所示:

var area = container.querySelector('textarea');
if (area.addEventListener) {
  area.addEventListener('input', function() {
    // event handling code for sane browsers
  }, false);
} else if (area.attachEvent) {
  area.attachEvent('onpropertychange', function() {
    // IE-specific event handling code
  });
}

input事件处理IE9 +,FF,Chrome,Opera和Safari,并onpropertychange处理IE8(它也适用于IE6和7,但存在一些错误)。

使用input和的优点onpropertychange是它们不会不必要地触发(如按CtrlShift键时);因此,如果您希望在文本区域内容更改时执行相对昂贵的操作,则可以采用这种方法

现在IE,一如既往,不支持这一个半称职的工作:既没有input,也不onpropertychange在IE火灾时,字符删除从文本区域。因此,如果您需要处理IE中字符的删除,请使用keypress(与使用keyup/ 相对keydown,因为即使用户按下并按住某个键,它们也只会触发一次)。

资料来源:http : //www.alistapart.com/articles/expanding-text-areas-made-elegant/

编辑:看来,即使上述方案并不完美,因为正确地在评论中指出:存在addEventListener于textarea的属性并没有暗示你与一个健全的浏览器工作; 类似地,存在attachEvent性并没有暗示IE。如果您希望代码确实是气密的,则应考虑更改它。有关指针,请参见Tim Down的评论


1
这是最好的方法。我不喜欢这里的推论(浏览器支持addEventListener并不意味着支持该input事件,反之亦然);特征检测会更好。有关问题的讨论,请参见此博客文章
蒂姆·唐

完全同意蒂姆对此的看法。oninput是我们应该这样做的方式,但是您可能不应该将其addEventListener用作浏览器支持的测试。+1。
本D

1
不同意,输入不会处理IE9。不幸的是,通过contextmenu剪切/粘贴也是输入,退格也是如此。我没有花时间去测试,但是我不会押注IE10 +可以解决该问题。
Stefan Steiger

1
@StefanSteiger,这就是为什么我的答案建议也使用该keypress事件在IE9(以及可能更高版本)中处理这种情况。
Vicky Chijwani

input事件处理程序也可以通过实现.oninputobject属性来定义。
处理

20
  • 对于Google-Chrome,oninput就足够了(在Windows 7上,版本22.0.1229.94 m进行了测试)。
  • 对于IE 9,oninput将捕获除通过contextmenu和Backspace剪切以外的所有内容。
  • 对于IE 8,除了oninput外,还需要onpropertychange来捕获粘贴。
  • 对于IE 9 + 8,需要onkeyup来捕获退格键。
  • 对于IE 9 + 8,onmousemove是我发现通过contextmenu进行剪切的唯一方法

未在Firefox上测试。

    var isIE = /*@cc_on!@*/false; // Note: This line breaks closure compiler...

    function SuperDuperFunction() {
        // DoSomething
    }


    function SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally() {
        if(isIE) // For Chrome, oninput works as expected
            SuperDuperFunction();
    }

<textarea id="taSource"
          class="taSplitted"
          rows="4"
          cols="50"
          oninput="SuperDuperFunction();"
          onpropertychange="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();"
          onmousemove="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();"
          onkeyup="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();">
Test
</textarea>

1
很棒的函数名:)
乔纳斯·格罗格(JonasGröger)

8

我知道这不完全是您的问题,但我认为这可能有用。对于某些应用程序,最好不要每次按一次键都启用更改功能。这可以通过以下方式实现:

var text = document.createElement('textarea');
text.rows = 10;
text.cols = 40;
document.body.appendChild(text);

text.onkeyup = function(){
var callcount = 0;
    var action = function(){
        alert('changed');
    }
    var delayAction = function(action, time){
        var expectcallcount = callcount;
        var delay = function(){
            if(callcount == expectcallcount){
                action();
            }
        }
        setTimeout(delay, time);
    }
    return function(eventtrigger){
        ++callcount;
        delayAction(action, 1200);
    }
}();

这通过测试是否在某个延迟时间内触发了最近的事件而起作用。祝好运!


1
为“节流”延迟动作+1!我在我的应用程序中使用了类似的东西。
psulek

7

我知道这个问题是特定于JavaScript的,但是,似乎没有一种好的,干净的方法可以始终检测当前所有浏览器中的文本区域何时发生变化。我了解到jquery已经为我们解决了这个问题。它甚至可以处理对文本区域的上下文菜单更改。无论输入类型如何,都使用相同的语法。

    $('div.lawyerList').on('change','textarea',function(){
      // Change occurred so count chars...
    });

要么

    $('textarea').on('change',function(){
      // Change occurred so count chars...
    });

4
我发现change事件与jQuery相比没有比与普通JS更加一致。我使用的是jQuery bind("input cut paste"...,它的工作原理很像-使用键盘或上下文菜单输入,剪切和粘贴;甚至拖放文本。
劳伦斯多尔

2
不幸的是,FF不会change为触发事件textarea
dma_k 2014年

4

您可以在textarea更改时收听事件,并根据需要进行更改。这是一个例子。

(() => {
	const textArea = document.getElementById('my_text_area');
  textArea.addEventListener('input', () => {
    let textLn =  textArea.value.length;
    if(textLn >= 100) {
      textArea.style.fontSize = '10pt';
    }

  })
})()
<html>
<textarea id='my_text_area' rows="4" cols="50" style="font-size:40pt">
This text will change font after 100.
</textarea>
</html>


1

如果将Keyup与HTML5输入验证/样式属性配对,就足够了。因此,创建一个模式(regex)来验证输入并根据.checkValidity()状态采取行动。像下面这样的东西可以工作。在您的情况下,您需要一个正则表达式匹配长度。我的解决方案正在此处在线使用/可演示。

<input type="text" pattern="[a-zA-Z]+" id="my-input">

var myInput = document.getElementById = "my-input";

myInput.addEventListener("keyup", function(){
  if(!this.checkValidity() || !this.value){
    submitButton.disabled = true;
  } else {
    submitButton.disabled = false;
  }
});

0

我用于IE 11且没有jquery且仅用于单个textarea的代码:

Javascript:

// Impede que o comentário tenha mais de num_max caracteres
var internalChange= 0; // important, prevent reenter
function limit_char(max)
{ 
    if (internalChange == 1)
    {
        internalChange= 0;
        return;
    }
    internalChange= 1;
    // <form> and <textarea> are the ID's of your form and textarea objects
    <form>.<textarea>.value= <form>.<textarea>.value.substring(0,max);
}

和html:

<TEXTAREA onpropertychange='limit_char(5)' ...

-1

试试这个。这很简单,并且因为它是2016年,所以我确信它可以在大多数浏览器上使用。

<textarea id="text" cols="50" rows="5" onkeyup="check()" maxlength="15"></textarea> 
<div><span id="spn"></span> characters left</div>

function check(){
    var string = document.getElementById("url").value
    var left = 15 - string.length;
    document.getElementById("spn").innerHTML = left;
}

因此,您通过id获取url,但未在代码中显示。
AbsoluteƵERØ

-8

最好的办法是设置一个要在给定时间内调用的函数,然后使用此函数检查文本区域的内容。

self.setInterval('checkTextAreaValue()', 50);

7
轮询是一个非常糟糕的主意。它将破坏性能。此外,像其他已发布的一样,存在一些解决方案
Pier-Olivier Thibault,2012年

2
这是21世纪。没有浏览器应该每50毫秒处理一次字符串比较。缓存您的选择器,这是一个完全可以接受的解决方案。
空性2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.