简体   繁体   English

如何可靠地取消 compositionstart 事件?

[英]How can I reliably cancel a compositionstart event?

When only targetting Google Chrome, is it possible to cancel the compositionstart event?仅针对 Google Chrome 时,是否可以取消 compositionstart 事件? According to this draft it is cancelable, however, when using e.preventDefault() as such根据这个草案,它是可以取消的,但是,当使用e.preventDefault()

document.querySelector("textarea").addEventListener('compositionstart', (e) => {
    e.preventDefault();
});

Chrome still begins a composition when pressing ´ for example.例如,当按下´时,Chrome 仍会开始组合。

I currently have a reasonably reliable way of stopping this by using我目前有一种相当可靠的方法来阻止这种情况,方法是使用

 document.querySelector("textarea").addEventListener('compositionstart', function() { this.blur(); setTimeout(() => this.focus(), 0); });
 <textarea>Spam ´ here</textarea>

As long as my textarea does not contain any breaks, this 'cancels' the compositionstart event when pressing ´ .只要我的 textarea 不包含任何中断,这会在按下´时“取消”compositionstart 事件。 My problem right now is that if I spam the ´ key for a few seconds, my method does not always cancel the event and this causes a ´ to appear.我现在的问题是,如果我在几秒钟内向´键发送垃圾邮件,我的方法并不总是会取消事件,这会导致出现´

What I'm doing also feels very hacky, so I was wondering if there is a good, possibly cross-browser, way of stopping the compositionstart event?我正在做的事情也感觉很hacky,所以我想知道是否有一个好的,可能跨浏览器的方式来停止 compositionstart 事件?

I've found that a (also hacky) solution against spamming was increasing the timeout to 20 milliseconds.我发现针对垃圾邮件的(也是骇人听闻的)解决方案是将超时时间增加到 20 毫秒。 This timeout should be short enough that the user won't notice the blur and refocus, but it's long enough to stop the spamming.这个超时时间应该足够短,以至于用户不会注意到模糊和重新聚焦,但它足够长以阻止垃圾邮件。

If I store the selection and range when the compositionstart event is fired, I can then reuse them after the blur, so that I won't get weird side-effects that I was originally having.如果我在触发 compositionstart 事件时存储选择和范围,然后我可以在模糊之后重用它们,这样我就不会得到我最初拥有的奇怪的副作用。 For my original case of a textarea this solution does not work, because for this a custom implementation of the window.getSelection() method is needed.对于我原来的textarea案例,此解决方案不起作用,因为为此需要window.getSelection()方法的自定义实现。 However, it does work for a div with contenteditable enabled.但是,它确实适用于启用contenteditablediv

Anyways, this code works for me in Chrome 84 and Firefox 78:无论如何,这段代码在 Chrome 84 和 Firefox 78 中适用于我:

 document.querySelector("#root").addEventListener('compositionstart', function () { let sel = window.getSelection(); let range = sel.getRangeAt(0); this.blur(); window.getSelection().removeAllRanges(); setTimeout(() => { sel.addRange(range); }, 20); });
 <div id='root' contenteditable="true" style="outline: none"> <p>Spam ´ here</p> </div>

I'm not very satisfied with the solution, but I've not found anything better yet.我对解决方案不是很满意,但我还没有找到更好的解决方案。 Hopefully someone else will find a more valid way of going about this.希望其他人会找到一种更有效的方法来解决这个问题。

This method does not work on phones, which fire the compositionstart event when the div receives focus.此方法不适用于手机,手机会在div获得焦点时触发 compositionstart 事件。

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

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