【问题标题】:make document.execCommand('insertText', false, 'message') work with draftjs?使 document.execCommand('insertText', false, 'message') 与 Draftjs 一起使用?
【发布时间】:2020-08-29 11:56:18
【问题描述】:

我正在开发一个需要将文本插入contenteditable="true" div 的应用程序(准确地说是基于Draftjs 的文本字段)。

现在我知道 Draft.js 使用 react 并且应该以这种方式使用它,但在这种情况下,应用程序已经存在,这是一个可以使用它的第三方电子应用程序。

我正在处理在 macOS 上回复的内联通知,因此我需要将该回复文本粘贴到 DraftJS 字段中,但是,当我这样做时:

document.querySelector('div[contenteditable="true"]').focus();
document.execCommand('insertText', false, 'message');

它抛出一个错误:

我能够使用:

const event = document.createEvent('TextEvent');
event.initTextEvent('textInput', true, true, window, 'message', 0, locale);

但如果消息包含表情符号,此 API 已弃用且无法正常工作。

有什么方法可以做到这一点不会导致错误? 我发现应该替换 initTextEvent 的新 API 只是 new Event()(参见 docs),但我不知道它是否支持 textInput 事件。

要使用它,您只需转到 https://draftjs.org/ 并在 chrome 开发工具中使用它。

我真的很感谢这里的一些帮助,因为我不知道该怎么做才能让它工作。另外,我知道人们是 jquery 的粉丝,但我更喜欢原生 js 解决方案(尽管欢迎任何解决方案)。

编辑:

请注意: 我没有使用react,我要修改的输入字段(draftjs)正在使用react,我想使用本机js向其中输入文本。

编辑 2:

对于遇到此问题的其他人,我想将文本插入 Facebook Messenger 文本字段(使用 Draftjs)。

我设法找到了一个可行的解决方法。 它确实使用了已弃用的 API (event.initTextEvent),但这是我发现的唯一可行的方法,即使使用表情符号也是如此。 如果您对此有更好的解决方案,请发布答案。 它的工作原理是这样的:

async function sendReply(message: string): Promise<void> {
       const inputField = document.querySelector('[contenteditable="true"]') as HTMLElement;
       if (inputField) {
               const previousMessage = inputField.textContent;
               // Send message
               inputField.focus();
               await insertMessageText(message, inputField);
               (await elementReady('._30yy._38lh._39bl')).click();
               // Restore (possible) previous message
               if (previousMessage) {
                       insertMessageText(previousMessage, inputField);
               }
       }
}

function insertMessageText(text: string, inputField: HTMLElement): void {
       // Workaround: insert placeholder value to get execCommand working
       if (!inputField.textContent) {
               const event = document.createEvent('TextEvent');
               event.initTextEvent('textInput', true, true, window, '_', 0, '');
               inputField.dispatchEvent(event);
       }

       document.execCommand('selectAll', false, undefined);
       document.execCommand('insertText', false, text);
}

这是打字稿代码,因此您可能需要将其更改为使用 js。

它的工作原理是使用 event.initTextEvent 在 textField 中插入一个占位符值,然后将该文本替换为:

document.execCommand('selectAll', false, undefined);
document.execCommand('insertText', false, 'text');

在 Chrome 中测试:版本 71.0.3578.98

【问题讨论】:

  • 你为什么不添加一个自定义事件,而不是在反应代码中监听它,而不是调用正确的修改器方法?
  • 我没有使用 react,就是这样,如果我使用 react 来做到这一点,那就很容易了。这是一个现有的反应应用程序(使用 Draftjs 文本字段系统),我需要使用常规 javascript 输入文本。而且我知道 react 使用虚拟 DOM,但我应该能够以某种方式将通知文本放入该字段。它使用第二种方法工作,但已被弃用并且存在表情符号问题。 execCommand 方法可以工作,但会引发一个错误,使其无法正常工作。

标签: javascript reactjs electron draftjs execcommand


【解决方案1】:

尽管这个问题是很久以前提出的并且@JoniVR 找到了解决方法,但这可能对其他人有所帮助。

我在开发扩展程序时也遇到了类似的问题。我还尝试了方法 document.execCommand('insertText', false, text)。它在 LinkedIn 上有效,但在 Facebook 上无效。它在错误的节点中插入文本。虽然document.execCommand API 在某些地方有效,但现在已经过时了。

对于 Facebook 和任何其他使用 drafjs 编辑器的网站,我们需要使用 dataTransferclipBoardEvent API 发送粘贴事件,以使 Draftjs 认为文本已被粘贴并进行相应处理。

const dataTransfer = new DataTransfer();

function dispatchPaste(target, text) {
  // this may be 'text/html' if it's required
  dataTransfer.setData('text/plain', text);

  target.dispatchEvent(
    new ClipboardEvent('paste', {
      clipboardData: dataTransfer,

      // need these for the event to reach Draft paste handler
      bubbles: true,
      cancelable: true
    })
  );

  // clear DataTransfer Data
  dataTransfer.clearData();
}

如果需要更多信息,请查看此link

【讨论】:

  • 像魅力一样工作。感谢分享!
  • @massanishi 很高兴它对你有所帮助。
  • 这个函数是如何被调用的?我的代码是否调用dispatchPaste
  • @DanielKaplan 是的。你需要调用这个函数dispatchPaste。
  • 谢谢!这适用于其他编辑器,FWIW。比document.execCommand('insertText', false, text);容易得多
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-17
  • 1970-01-01
  • 2021-01-04
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 2017-06-01
相关资源
最近更新 更多