如何可靠地拦截(并取消)contenteditable中的所有输入?

问题描述 投票:0回答:1

我需要捕获

contenteditable
元素中的所有输入并处理代码中的输入。基本上,我需要的是防止输入事件更改元素中的数据并知道要插入哪些数据。

我尝试了几乎所有可能的事件,但我总是遇到一些意想不到的行为。

例如。

第一个也是最明显的 -

keydown
事件。它适用于桌面浏览器,几乎不适用于移动设备,并且完全忽略输入法编辑器(IME、win/meta + .)。

接下来是

textInput
活动。同样的问题,但使用 IME 效果更好一些。

现在我发现

beforeInput
可能是更通用的解决方案。我尝试在寻找
inputType
(它可以告诉当前操作 - insertContent、removeWordForward 等)和
data
属性时使用它,但它在 Safari 中不能完全工作(并且我无法调试它)现在)。而且 IME 也不可靠。

奖金回合是自定义移动键盘,如 Microsoft Swift Keyboard,它的行为绝对不可预测,我不知道如何处理。例如,它可以具有单词自动完成功能 - 无论如何都没有关于此的信息。

也许有解决方法?我尝试使用文本编辑器检查开源存储库,这看起来确实是一项不平凡的任务,因为我发现它们使用我列出的每个事件,并且它们有很多逻辑来处理它们

javascript dom-events contenteditable text-processing
1个回答
0
投票

引用OP的问题...

“基本上,我需要的是防止输入事件更改元素中的数据,并知道要插入哪些数据。”

这可以简单地通过查询具有

contenteditable
属性并且此外真正内容可编辑的所有元素来实现。

可以将每个元素节点的默认状态存储在例如通过节点引用的

WeakMap
实例,该引用引用具有例如元素的原始
innerHTML
textContent
值的对象。

如果发生基于“输入”事件的内容更改,将立即通过设置原始

innerHTML
值来恢复默认值。

// the node reference based storage of editable element's text-contents.
const editableContentStorage = new WeakMap;

function suppressEditableTextContentChange(evt) {
  const { currentTarget } = evt;
debugger;
  const {
    defaultHtml,
    defaultText,
  } = editableContentStorage.get(currentTarget);

  const changedContent = currentTarget.textContent;

  // immediately restore default content.
  currentTarget.innerHTML = defaultHtml;

  console.log({ defaultText, changedContent });
}


document
  // for every element which features
  // a `contenteditable` attribute ...
  .querySelectorAll('[contenteditable]')

  // ... enable the handling of a custom
  // 'input:datachange' event in case of
  // an editable element.
  .forEach(elmNode => {
    if (elmNode.contentEditable === 'true') {

      editableContentStorage
        .set(elmNode, {
          defaultHtml: elmNode.innerHTML,
          defaultText: elmNode.textContent,
        });

      elmNode
        .addEventListener('input', suppressEditableTextContentChange);
    }
  });
body { margin: 0; }
h2 { margin: 5px 0; font-size: 1.1em; }
p { margin: 5px 0; }
article { width: 20%; }
.as-console-wrapper { left: auto!important; width: 76%; min-height: 100%!important; }
<article contenteditable>
  <h2>Some header copy</h2>
  <p>Lorem ipsum dolor sit amet.</p>
  <p>
    The quick <b>brown fox</b> jumps over the
    <b>
      <em>lazy</em>
      dog
    </b>.
  </p>
</article>

© www.soinside.com 2019 - 2024. All rights reserved.