Как я могу надежно отменить событие запуска композиции? - PullRequest
0 голосов
/ 01 августа 2020

При таргетинге только на Google Chrome можно ли отменить событие запуска композиции? Согласно этот черновик его можно отменить, однако при использовании e.preventDefault() как такового

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

Chrome по-прежнему начинает композицию при нажатии ´, например.

В настоящее время у меня есть достаточно надежный способ остановить это, используя

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

Пока мое текстовое поле не содержит разрывов, это «отменяет» событие Compositionstart при нажатии ´. Моя проблема сейчас в том, что если я спамлю клавишу ´ в течение нескольких секунд, мой метод не всегда отменяет событие, и это вызывает появление ´.

То, что я делаю, тоже ощущается очень хакерский, поэтому мне было интересно, есть ли хороший, возможно, кроссбраузерный способ остановить событие Compositionstart?

1 Ответ

0 голосов
/ 01 августа 2020

Я обнаружил, что (тоже хакерское) решение против спама увеличивало таймаут до 20 миллисекунд. Этот тайм-аут должен быть достаточно коротким, чтобы пользователь не заметил размытия и перефокусировки, но его достаточно, чтобы остановить рассылку спама.

Если я сохраню выбор и диапазон при срабатывании события Compositionstart, я могу затем повторно используйте их после размытия, чтобы у меня не было странных побочных эффектов, которые были у меня изначально. В моем первоначальном случае с textarea это решение не работает, потому что для этого требуется специальная реализация метода window.getSelection(). Однако он работает для div с включенным contenteditable.

В любом случае, этот код работает для меня в 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>

Не очень доволен решением, но лучше пока не нашел. Надеюсь, кто-то другой найдет более действенный способ сделать это.

Этот метод не работает на телефонах, которые запускают событие Compositionstart, когда div получает фокус.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...