如何检测按下的键是否会在 中生成字符文本框?

发布于 2024-10-02 18:56:48 字数 1692 浏览 10 评论 0原文

我有一个常规文本框:

<input type="text"> 

我使用 jQuery 来处理与按键相关的事件:

$("input:text").keydown(function() {
    // keydown code
}).keypress(function() {
    // keypress code
}).keyup(function() {
    // keyup code
});

用户专注于文本框并按下键盘上的各种键(通常是:字母、数字、SHIFT、BACKSPACE、SPACE、.. .)。我需要检测用户何时按下将增加文本框值长度的键。例如,“A”键将增加它,“SHIFT”键则不会。

我记得看过 PPK 的一次演讲,他提到了两者之间的区别。它与事件有关 - keydown 与 keypress - 并且可能与事件属性有关 - key、c​​har、keyCode。

更新!

我需要在 keydown 或 keypress 处理程序中了解此信息。我等不及 keyup 事件发生。

为什么我需要这个:

我有一个文本框,其大小根据用户输入动态变化。您可以看一下这个演示: http://vidasp.net/tinydemos/ variable-size-text-box.html

在演示中,我有一个 keydown 和 keyup 处理程序。 keyup 处理程序根据输入值调整文本框大小。但是,keydown 处理程序将大小设置为比输入值大 1 个字符。我这样做的原因是,如果不这样做,字符就会溢出到文本框之外,并且只有当用户松开按键时,文本框才会展开。这看起来很奇怪。这就是为什么我必须预见新字符 - 在每个按键上我都会放大文本框,因此,在字符出现在文本框中之前。正如您在演示中看到的,这个方法看起来很棒。

然而,问题是 BACKSPACE 和 ARROW 键 - 它们也会在 keydown 时展开文本框,并且只有在 keyup 时文本框大小才会被纠正。

解决方法:

解决方法是手动检测 BACKSPACE、SHIFT 和 ARROW 键并据此采取行动:

// keydown handler
function(e) {
    var len = $(this).val().length;
    if (e.keyCode === 37 || e.keyCode === 39 ||
        e.keyCode === 16) { // ARROW LEFT or ARROW RIGHT or SHIFT key
        return;
    } else if (e.keyCode === 8) { // BACKSPACE key
        $(this).attr("size", len <= 1 ? 1 : len - 1);
    } else {
        $(this).attr("size", len === 0 ? 1 : len + 1);
    }
}

这适用于(并且看起来很棒)退格键、Shift 键、向左箭头和向右箭头。但是,我想要一个更强大的解决方案。

I have a regular text-box:

<input type="text"> 

I use jQuery to handle key-related events:

$("input:text").keydown(function() {
    // keydown code
}).keypress(function() {
    // keypress code
}).keyup(function() {
    // keyup code
});

The user focuses on a text-box and presses various keys on his keyboard (the usual ones: letters, numbers, SHIFT, BACKSPACE, SPACE, ...). I need to detect when the user presses a key that is going to increase the length of the text-box value. For example, the "A" key will increase it, the "SHIFT" key wont.

I remember watching a lecture by PPK where he mentioned the difference between those two. It has something to do with the event - keydown vs. keypress - and possibly with the event properties - key, char, keyCode.

Update!

I need to know this information within the keydown or keypress handlers. I cannot wait for the keyup event to occur.

Why I need this:

I have a text-box which size dynamically changes based on the user input. You can have a look at this demo: http://vidasp.net/tinydemos/variable-size-text-box.html

In the demo, I have a keydown and keyup handler. The keyup handler adjusts the text-box size based on the input value. However, the keydown handler sets the size to be 1 character larger then the input value. The reason I do this is that if I didn't, then the character would overflow outside the text-box and only when the user would let go of the key, the text-box would expand. This looks weird. That's why I have to anticipate the new character - I enlarge the text-box on each keydown, ergo, before the character appears in the text-box. As you can see in the demo, this method looks great.

However, the problem are the BACKSPACE and ARROW keys - they will also expand the text-box on keydown, and only on keyup the text-box size will be corrected.

A work-around:

A work-around would be to detect the BACKSPACE, SHIFT, and ARROW keys manually and act based on that:

// keydown handler
function(e) {
    var len = $(this).val().length;
    if (e.keyCode === 37 || e.keyCode === 39 ||
        e.keyCode === 16) { // ARROW LEFT or ARROW RIGHT or SHIFT key
        return;
    } else if (e.keyCode === 8) { // BACKSPACE key
        $(this).attr("size", len <= 1 ? 1 : len - 1);
    } else {
        $(this).attr("size", len === 0 ? 1 : len + 1);
    }
}

This works (and looks great) for BACKSPACE, SHIFT, ARROW LEFT and ARROW RIGHT. However, I would like to have a more robust solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

污味仙女 2024-10-09 18:56:48

我认为这可以完成工作,或者如果不能完成工作,则非常接近,只需要进行少量调整。您必须记住的是,您根本无法可靠地判断可能在 keydownkeyup 事件中键入的任何字符:所有这些都必须是在 keypress 处理程序中完成。关键事件的权威资源是 http://unixpapa.com/js/key.html

还需要考虑粘贴,此代码无法处理。您需要有单独的 paste 事件处理程序(尽管 Firefox <3.0、Opera 和非常旧的 WebKit 浏览器不支持此事件)。您的粘贴处理程序中需要一个计时器,因为在 JavaScript 中不可能访问要粘贴的内容。

function isCharacterKeyPress(evt) {
    if (typeof evt.which == "undefined") {
        // This is IE, which only fires keypress events for printable keys
        return true;
    } else if (typeof evt.which == "number" && evt.which > 0) {
        // In other browsers except old versions of WebKit, evt.which is
        // only greater than zero if the keypress is a printable key.
        // We need to filter out backspace and ctrl/alt/meta key combinations
        return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8;
    }
    return false;
}

<input type="text" onkeypress="alert(isCharacterKeyPress(event))">

This I think will do the job, or if not is very close and will need only minor tweaking. The thing you have to remember is that you can't reliably tell anything at all about any character that may be typed in a keydown or keyup event: that all has to be done in a keypress handler. The definitive resource for key events is http://unixpapa.com/js/key.html

You also need to consider pastes, which this code won't handle. You will need to have separate paste event handler (although this event isn't supported in Firefox < 3.0, Opera, and very old WebKit browsers). You'll need a timer in your paste handler since it's impossible in JavaScript to access the content that's about to be pasted.

function isCharacterKeyPress(evt) {
    if (typeof evt.which == "undefined") {
        // This is IE, which only fires keypress events for printable keys
        return true;
    } else if (typeof evt.which == "number" && evt.which > 0) {
        // In other browsers except old versions of WebKit, evt.which is
        // only greater than zero if the keypress is a printable key.
        // We need to filter out backspace and ctrl/alt/meta key combinations
        return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8;
    }
    return false;
}

<input type="text" onkeypress="alert(isCharacterKeyPress(event))">
活雷疯 2024-10-09 18:56:48

这是一个更简单的解决方案,对我来说效果很好:

document.addEventListener('keyup', event => {
  if (String.fromCharCode(event.keyCode).match(/(\w|\s)/g)) {
    //pressed key is a char
  } else {
    //pressed key is a non-char
    //e.g. 'esc', 'backspace', 'up arrow'
  }
});

这不需要探测 DOM 元素(这会增加延迟和丑陋)。

更新的示例使用:

Here's a much simpler solution which worked well for me:

document.addEventListener('keyup', event => {
  if (String.fromCharCode(event.keyCode).match(/(\w|\s)/g)) {
    //pressed key is a char
  } else {
    //pressed key is a non-char
    //e.g. 'esc', 'backspace', 'up arrow'
  }
});

This doesn't require probing a DOM element (which would add latency and ugliness).

Updated example use:

久夏青 2024-10-09 18:56:48

我能找到的可能的解决方案是检查事件中密钥的长度。

例如:-

<input type="text" id="testId" onkeyup="keyChecking(event)" />

<script type="text/javascript">
function keyChecking(event) {

    if (event.key.length == 1) {
        alert("key produced character " + event.key);
    } else {
        alert("Key DOES NOT produce character");

        const alphabets = "AZaz09";
        const key = event.key;
        var notEvenASymbol = false;

        for (let i = 0; i < key.length; i++) {
            var charCode = key.charCodeAt(i);
            if ((charCode >= alphabets.charCodeAt(0) && charCode <= alphabets.charCodeAt(1)) ||
                (charCode >= alphabets.charCodeAt(2) && charCode <= alphabets.charCodeAt(3)) ||
                (charCode >= alphabets.charCodeAt(4) && charCode <= alphabets.charCodeAt(5))
            ) {
                notEvenASymbol = true;
                console.log(charCode);
                break;
            }
        }

        if (notEvenASymbol) {
            alert("Key DOES NOT produce even a symbol");
        }
        console.log(event.key);

    }
}    
</script>

因此,如果您按任何字符/符号,event.key 将包含该字符,并且其长度将为 1。如果您按字符 V,则 < code>event.key 将具有值 V,但如果您按 Enter 键,则它将包含值 Enter,如果您按 Shift,则它将包含值 Shift< /em> 等等。因此,如果一个键不产生字符,那么它的长度将大于1。

更新

键盘中的一些特殊键产生符号,它的长度可能大于1,所以我修改了代码即使它不是一个符号,它也可以发出警报。例如:-

The possible solution I can find is checking the length of key in event.

Eg:-

<input type="text" id="testId" onkeyup="keyChecking(event)" />

<script type="text/javascript">
function keyChecking(event) {

    if (event.key.length == 1) {
        alert("key produced character " + event.key);
    } else {
        alert("Key DOES NOT produce character");

        const alphabets = "AZaz09";
        const key = event.key;
        var notEvenASymbol = false;

        for (let i = 0; i < key.length; i++) {
            var charCode = key.charCodeAt(i);
            if ((charCode >= alphabets.charCodeAt(0) && charCode <= alphabets.charCodeAt(1)) ||
                (charCode >= alphabets.charCodeAt(2) && charCode <= alphabets.charCodeAt(3)) ||
                (charCode >= alphabets.charCodeAt(4) && charCode <= alphabets.charCodeAt(5))
            ) {
                notEvenASymbol = true;
                console.log(charCode);
                break;
            }
        }

        if (notEvenASymbol) {
            alert("Key DOES NOT produce even a symbol");
        }
        console.log(event.key);

    }
}    
</script>

So, if you press any characters/symbols, the event.key will contain that character and its length will be 1. If you press character V then the event.key will have value V but if you press enter key then it will contain value Enter, if you press shift then Shift and so on. Therefore, if a key doesn't produce a character then its length will be greater than 1.

Updated

Some special keys in the keyboard produce symbol and its length may be greater than 1 so I modified the code so that it can alert even if it's not a symbol. Eg:- ???? its length is 2. Some mobile keyboards have shortcut keys for such symbols.

A non character/symbol key in the keyboard will always be a combination of alphabets, number characters or of both, Eg:- F2, Shift.

Thanks @Vicky Chijwani for bringing attention to this scenario.

伏妖词 2024-10-09 18:56:48

要在 keydown 处理程序中检测按下的键是否产生单个 unicode 字符,您可以使用正则表达式的 ES6 unicode u 标志。

我们使用 KeyboardEvent.key 属性,该属性返回按下的键的值。根据文档:

如果按下的键具有打印表示形式,则返回值是一个非空 Unicode 字符串,其中包含该键的可打印表示形式。

inputElement.addEventListener("keydown", ({ key }) => {
  if (/^.$/u.test(key)) {
    // `key` matches a single unicode character
  }
});

该解决方案不处理粘贴...

To detect in a keydown handler if a pressed key produces a single unicode character, you can use the ES6 unicode u flag for regular expressions.

We use the KeyboardEvent.key property, which returns the value of the pressed key. According to the docs:

If the pressed key has a printed representation, the returned value is a non-empty Unicode character string containing the printable representation of the key.

inputElement.addEventListener("keydown", ({ key }) => {
  if (/^.$/u.test(key)) {
    // `key` matches a single unicode character
  }
});

The solution does not handle pasting...

风和你 2024-10-09 18:56:48

好吧,我想我已经明白了。该解决方案有点hackish,但实际上效果很好。

在 keydown 上,执行 1 毫秒的 setTimeout,调用一个函数来检查/更改输入框的长度。

function checkLength() {
    var len = $("input:text").val().length;
    $("input:text").attr("size", len === 0 ? 1 : len + 1);
}

$("input:text").attr({
    "size": 1,
    "spellcheck": false
}).keydown(function() {
    setTimeout(checkLength, 1);
});
p { padding:50px; }
        
input { 
    border:1px solid gray;
    padding:6px; 
    font-size:26px;
    font-family:monospace;
    outline:none; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<input type="text"></input>

它似乎工作得很好,特别是在你的版本没有的一些地方(例如退格键、CTRL+V 或选择一大堆文本并点击删除)

编辑:即使 setTimeout 延迟 0 毫秒似乎也有效!

OK, I think I've got it. The solution is a bit hackish, but actually works really well.

On keydown, do a setTimeout for 1 millisecond, that calls a function to check/change the length of your input box.

function checkLength() {
    var len = $("input:text").val().length;
    $("input:text").attr("size", len === 0 ? 1 : len + 1);
}

$("input:text").attr({
    "size": 1,
    "spellcheck": false
}).keydown(function() {
    setTimeout(checkLength, 1);
});
p { padding:50px; }
        
input { 
    border:1px solid gray;
    padding:6px; 
    font-size:26px;
    font-family:monospace;
    outline:none; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<input type="text"></input>

It seems to work really well, especially in a few places where your version doesn't (e.g. backspace, CTRL+V, or selecting a whole bunch of text and hitting delete)

Edit: Even setTimeout with a 0ms delay seems to work!

挽心 2024-10-09 18:56:48

您应该在 keydown 函数中使用 keyEventArgs.Key 属性,这将返回取决于系统的数值。

这里有一个链接,其中包含针对不同浏览器和操作系统的不同密钥代码:

http://www. quirksmode.org/js/keys.html

You should use the property keyEventArgs.Key in the keydown function, this will return the numeric value that will depend on the system.

here is a link that has the different key codes for the different browsers and OS:

http://www.quirksmode.org/js/keys.html

生活了然无味 2024-10-09 18:56:48

这可能不是您正在寻找的方法,但您可以在 keydown 函数中检查 this.value.length 的值。返回值是添加新字符之前输入字段中文本的长度。因此,如果您在 keyup 函数中再次检查长度,如果用户按下一个字符,则长度会更大,但如果用户按下 Shift 键,则长度相同。

This may not be the method that you're looking for, but you can just check the value of this.value.length in your keydown function. The return value is the length of the text in the input field BEFORE the new character is added. So if you check the length again in the keyup function, it will be greater if the user pressed a character, but the same if the user hit the shift key.

对风讲故事 2024-10-09 18:56:48

我假设您正在对输入字段的长度设置一个计数器,在这种情况下您不需要那么花哨,您可以继续将字段的长度分配给变量,当用户到达您的max length 只允许他们按删除或退格键,如下所示:

$("input:text").keypress(function() {
var current = $(this).val().length;
if (current >= 130) {
if (e.which != 0 && e.which != 8) {
e.preventDefault();
}
}
}

您也可以使用 current 变量来显示计数器,或者执行 maxlength - current 来倒计时剩余多少个字符

I presume you are setting up a counter on the length of an input field, in which case you don't need to be so fancy, you can just keep assigning the length of the field to a variable, and when the user gets to your max length only allow them to press delete or backspace like so:

$("input:text").keypress(function() {
var current = $(this).val().length;
if (current >= 130) {
if (e.which != 0 && e.which != 8) {
e.preventDefault();
}
}
}

You can use the current variable to display the counter as well, or do maxlength - current to do a countdown of how many charachters are left

不离久伴 2024-10-09 18:56:48

您的目标是保持文本框大于已输入的文本。

我将通过计划在文本框中留出两个额外字符(而不是一个)的空间来实现这一目标。那么:

// pseudo-code.... 
old_len = textbox.value.length
keyUp function() {
  var new_len = textbox.value.length
  if (new_len != old_len) {
    old_len = new_len
    textbox.style.size = new_len + 2 // pseudo code.
  }
}

上述的好处是你不需要深入按键码的深渊。

Your goal of keeping the textbox larger than the text that has been entered into it.

I'd accomplish this by planning on having room for two additional characters (not one) in the text box. Then:

// pseudo-code.... 
old_len = textbox.value.length
keyUp function() {
  var new_len = textbox.value.length
  if (new_len != old_len) {
    old_len = new_len
    textbox.style.size = new_len + 2 // pseudo code.
  }
}

The advantage of the above is that you don't need to descend into the nether world of keycodes.

小镇女孩 2024-10-09 18:56:48

不确定所有可能的键盘,但在我的键盘中,我注意到将“keypress”事件(不要使用 keydown 或 keyup)与 event.key 结合将仅返回可打印的字符,唯一的例外是“Enter”键将返回单词“Enter”,

所以我想出了以下简单的解决方案:

document.addEventListener('keypress', (event) => {
    if(event.key && event.key != 'Enter'){
      console.log('this is a character')
    }
});

此解决方案似乎也忽略了其他答案无法处理的快捷键,例如 ctrl+c 或 ctrl+v

注意:在 mozilla 和brave 中进行了测试,我想看看其他浏览器的结果是什么(请评论)

Not sure about all possible keyboards, but in my keyboard I noticed that combining the "keypress" event (don't use keydown or keyup) with event.key will return a character only if it's printable, the only exception is the "Enter" key which will return the word "Enter"

so I come up with the following simple solution:

document.addEventListener('keypress', (event) => {
    if(event.key && event.key != 'Enter'){
      console.log('this is a character')
    }
});

This solution seems to also ignore shortcuts like ctrl+c or ctrl+v which other answers don't handle

Note: tested in mozilla and brave, I would like to see what is the result in other browsers (please comment)

林空鹿饮溪 2024-10-09 18:56:48

基于我创建的其他答案:

export function producesCharacter(event: React.KeyboardEvent<HTMLInputElement>) {
   return !event.ctrlKey && !event.altKey && event.key.length === 1;
}

由于弃用警告,其他解决方案可能无法在 React 中工作

Based on other answers I created following:

export function producesCharacter(event: React.KeyboardEvent<HTMLInputElement>) {
   return !event.ctrlKey && !event.altKey && event.key.length === 1;
}

Other solutions may not work in React due to deprecation warnings

戏舞 2024-10-09 18:56:48

你可以这样做:

$("input:text").on("input", (e) => {
  e.target.size = e.target.value.length
})

因为:"输入事件触发当 、 或 元素的值发生更改时。”

这也将处理粘贴和删除。

一件事:在您的示例中,您将每个字符的大小增加 1。这种方法的问题是字符宽度是可变的并且取决于所使用的字体。它不会完全准确,但仍然有效

You could do something like this:

$("input:text").on("input", (e) => {
  e.target.size = e.target.value.length
})

Because: "The input event fires when the value of an , , or element has been changed."

This will also handle pasting and deleting.

One thing: In your example you are incrementing the size by 1 per character. The problem with this approach is that character width is variable and dependent on the font used. It won’t be totally accurate, but will still work

一瞬间的火花 2024-10-09 18:56:48

您可以订阅“InputEvent”,然后获取“data”属性。例如

input.addEventListener('beforeinput', (event) => {
    const data = event.data;

    // if "data" is present - user enter some character
    // if "data" is NOT present - user tap non character key (e.g. delete, shift and other)
    if(data) {
        const isAllow = /\d/.test(data);

        if(!isAllow) {
            e.preventDefault();
        }
    }
})

更多信息

  1. 事件。数据 - https://developer.mozilla.org/en-US/docs/Web/API/InputEvent/data
  2. beforeinput 事件 - https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/beforeinput_event

You can subscribe to "InputEvent" and then get "data" prop. For example

input.addEventListener('beforeinput', (event) => {
    const data = event.data;

    // if "data" is present - user enter some character
    // if "data" is NOT present - user tap non character key (e.g. delete, shift and other)
    if(data) {
        const isAllow = /\d/.test(data);

        if(!isAllow) {
            e.preventDefault();
        }
    }
})

More info

  1. event.data - https://developer.mozilla.org/en-US/docs/Web/API/InputEvent/data
  2. beforeinput event - https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/beforeinput_event
忆伤 2024-10-09 18:56:48

我知道您想在“keyup”或“keydown”侦听器中解决它。但是,我遇到了与此类似的问题,并通过使用“input”事件监听器解决了它。它监听输入的变化并做出相应的改变。我想我会分享。

I understand that you wanted to solve it within "keyup" or "keydown" listeners. However, I came across an issue similar to this, and solved it by using the "input" eventListener. It listens for changes in the input and makes changes accordingly. Thought I would share.

偏闹i 2024-10-09 18:56:48

您可以检测“shift”等键并在显示之前将其删除

//remove some text in blacklist from input
function removeFromString(words, str) {
    return words.reduce((result, word) => result.replaceAll(word, ''), str)
}


var pureInput = "";



document.addEventListener("keydown", function(event) {

const black_List_Keys = ["Shift","Control","Alt","Enter","Backspace"];

pureInput = removeFromString(black_List_Keys,pureInput+event.key);

document.getElementById("demo").textContent = pureInput;


});
<h1 id="demo">Press Keys</h1>

<p>Try type this word using shift And char  like : <br> <b>T</b>ail<b>W</b>ind</p>

You can detect key like "shift" and remove before display

//remove some text in blacklist from input
function removeFromString(words, str) {
    return words.reduce((result, word) => result.replaceAll(word, ''), str)
}


var pureInput = "";



document.addEventListener("keydown", function(event) {

const black_List_Keys = ["Shift","Control","Alt","Enter","Backspace"];

pureInput = removeFromString(black_List_Keys,pureInput+event.key);

document.getElementById("demo").textContent = pureInput;


});
<h1 id="demo">Press Keys</h1>

<p>Try type this word using shift And char  like : <br> <b>T</b>ail<b>W</b>ind</p>

吲‖鸣 2024-10-09 18:56:48

以下代码使用正确的 .key 事件,而不是(过时的?)which 事件

if (/[a-zA-Z]/.test(e.key) && e.key.length == 1) {
    //keypress is character
}

The following code uses the correct .key event and not the (outdated?) which event

if (/[a-zA-Z]/.test(e.key) && e.key.length == 1) {
    //keypress is character
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文