简体   繁体   English

当在按键事件处理程序中聚焦textarea元素时,Firefox出现问题

[英]Firefox issue when focusing textarea element in keypress event handler

The following snippet works great in chrome/edge/safari. 以下代码段适用于chrome / edge / safari。 In Firefox the textarea gets focused, but the pressed character isn't being added to the textarea - the first character will be always missing. 在Firefox中, textarea变得集中,但没有将按下的字符添加到textarea -第一个字符将始终丢失。

 document.addEventListener('keypress', (event) => { document.querySelector('#input').focus(); }); 
 <textarea id="input"></textarea> 

How can I make this behave consistently across all browsers? 如何在所有浏览器中保持一致?

Here's how you can make it work without browser sniffing: When the keypress happens, bind a handler to the input event on the textarea, and also set a 0-ms timeout. 这是在没有浏览器嗅探的情况下使其工作的方法:发生按键时,将处理程序绑定到textarea上的input事件,并设置0毫秒超时。

If the browser accepted the pressed key for the textarea, the input handler will run before the timeout (because the input event fires synchronously). 如果浏览器接受了textarea的按下键,则input处理程序将在超时之前运行(因为input事件同步触发)。 If that happens, you know the browser has handled the keypress correctly, and you can cancel the timeout. 如果发生这种情况,则说明浏览器已正确处理了按键,并且可以取消超时。

Then, if the timeout fires, you know that the input event hasn't fired and thus the character hasn't been added to the textarea, and you do it programmatically. 然后, 如果超时触发,您会知道input事件尚未触发,因此尚未将字符添加到文本区域,因此可以通过编程方式进行操作。

In both the event handler and the timeout handler, you unbind the event handler – it should run at most once (per key press). 在事件处理程序和超时处理程序中,都取消绑定事件处理程序–它最多应运行一次(每次按键)。

 var textarea = document.getElementById("input"); document.addEventListener("keypress", function (event) { if (event.target === textarea) { return; } var eventHandler = function () { textarea.removeEventListener("input", eventHandler); clearTimeout(timeoutId); console.log("input event"); } var timeoutHandler = function () { var character = ("char" in event) ? event.char : String.fromCharCode(event.charCode); textarea.value += character; textarea.removeEventListener("input", eventHandler); console.log("timeout fired"); } timeoutId = setTimeout(timeoutHandler, 1); textarea.addEventListener("input", eventHandler); textarea.focus(); }); 
 <textarea id="input"></textarea> <p style="background: #ccc"> <b>Click here</b> to make sure the document is focused, but the textarea is not. Then press a key. </p> 

If you try the above snippet in Firefox, the console will say "timeout fired". 如果您在Firefox中尝试上述代码段,则控制台将显示“超时触发”。 In all other browsers it will say "input event". 在所有其他浏览器中,它将说“输入事件”。 In either case, your pressed key is added to the textarea. 无论哪种情况,您所按下的键都会添加到文本区域。

Some notes: 一些注意事项:

  • Technically, for consistent behavior you'd need to do more than just append the character to the end; 从技术上讲,对于一致的行为,您需要做的不仅仅是将字符追加到末尾。 you'd also have to look at things like cursor position and text selection. 您还必须查看光标位置和文本选择之类的内容。 This may be overkill however. 但是,这可能是过大的。

  • If you need to support really old browsers, you might want to do a feature check for availability of the input event. 如果需要支持真正的旧浏览器,则可能需要对input事件的可用性进行功能检查。

  • If you have other code that relies on the textarea changing synchronously upon keypress, you'll probably have to make updates there. 如果您有其他依赖文本区域的代码在按键时同步更改,则可能必须在那里进行更新。

While this code will not work if any other browsers share the same behavior as Firefox, the following code will add any key input, given that it is a character whose string length is 1, when the code is run on Firefox : 而如果任何其他浏览器共享相同的行为,火狐这个代码将无法正常工作,下面的代码将添加任何按键输入,因为它是一个字符,其字符串长度为1,当代码在Firefox上运行:

 var mozFocused = false; document.addEventListener('keypress', (event) => { document.querySelector('#input').focus(); var isFirefox = typeof InstallTrigger !== 'undefined'; if (isFirefox && !mozFocused && event.key.length === 1) { mozFocused = true; document.querySelector('#input').value += event.key; } }); document.querySelector('#input').addEventListener('blur', (event) => { mozFocused = false; }); 
 <textarea id="input"></textarea> 

Again, note that this does not guarantee it to work across all browsers, as this was a fix for Firefox specifically, but, if you see the same behavior occurring in other browsers, I used the answer from this SO post to detect the current browser the client is using (assuming it is in the list of the browsers that this post discusses): How to detect Safari, Chrome, IE, Firefox and Opera browser? 同样,请注意,这不能保证它能在所有浏览器上正常运行,因为这是专门针对Firefox的修复程序,但是,如果您看到其他浏览器中也发生了相同的行为,我将使用此SO帖子中的答案来检测当前浏览器客户端正在使用(假设它在本文讨论的浏览器列表中): 如何检测Safari,Chrome,IE,Firefox和Opera浏览器?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM