在更改之前获取contenteditable元素的textContent(或`beforeinput`)

时间:2018-03-14 10:26:58

标签: javascript contenteditable addeventlistener

我有<ol contenteditable=true>个元素,我想添加一个eventListener,以便之前在这些列表的任何<li>中进行任何更改,原始textContent(即是,任何改动之前的文本)被推到var alterations = []

我尝试过使用addEventListener("beforeinput", ...,如下所示:

&#13;
&#13;
window.alterations = [];

window.onload = () => {
  document.getElementById('main').addEventListener("beforeinput", () => {
    alert('event listened!');
    window.alterations.push(window.getSelection().anchorNode.parentElement.textContent);
    
    console.log(window.alterations);
  });
}
    
&#13;
<body>
<section id="main">
<ol contenteditable="true">
  <li>First</li>
  <li>Second</li>
  <li>Third</li>
  <li>Fourth</li>
</ol>
<ol contenteditable="true">
  <li>First</li>
  <li>Second</li>
  <li>Third</li>
  <li>Fourth</li>
</ol>
</section>
</body>
&#13;
&#13;
&#13;

beforeinput似乎不适用于contenteditable元素(如上面的代码所示,回调函数未执行)。只有input事件作为addEventListener的参数,但为时已晚,因为已经从原始文本中输入或删除了一个字母。

问题:如何通过contenteditable获取要更改的元素的原始文本?例如,如果我输入&#34; First&#34; <li>其他内容,例如&#34;不是第一个&#34;,如何推送textContent的原始<li>(===#34; First&#34;)到alterations数组?

编辑:我认为这是一个浏览器问题。 beforeinput适用于基于Chromium的浏览器,但不适用于基于Firefox的浏览器(如Firefox和PaleMoon)。我的quickfix是使用keydown而不是beforeinput。此代码适用于所有浏览器:

 for (let x of document.querySelectorAll('[contenteditable="true"]')) {
   x.addEventListener('keydown',() => {
     let originalText = window.getSelection().anchorNode.textContent; 
     console.log(originalText);
   });

但是每次按下任何键时都会触发一个不幸的问题,例如 Ctrl + Shift Alt 。我尝试keypress代替keydown,但我的基于Chromium的浏览器没有触发删除,而且任何&#34;上/下/左/右/&#34;按下的键也会触发代码。我想我可以使用charcode逐个处理这些例外情况,但除了使用keydown之外别无他法吗?

1 个答案:

答案 0 :(得分:1)

好的,这应该有效:

window.alterations = [];

window.onload = () => {
  document.getElementById('main').addEventListener("keydown", (event) => {
    //0 == delete in PaleMoon, 46 == delete in other browsers

    /* ALT is needed for some characters, like § and º, but to exclude ALT, META, etc.:
    if (event.altKey || event.metaKey) {return;} */

    if (event.key.length === 1 || ["Enter", "Delete", "Backspace"].includes(event.key)) {
      //when Ctrl is pressed, trigger only if Ctrl+V or Ctrl+X and ALT is not pressed:
      if (event.key.toLowerCase() !== 'v' && event.key.toLowerCase() !== 'x' && event.ctrlKey && !event.altKey) {return;}

      alert('event listened!');
      window.alterations.push(window.getSelection().anchorNode.parentElement.textContent);

      console.log(window.alterations);
    }
  });
}
<body>
  <section id="main">
    <ol contenteditable="true">
      <li>First</li>
      <li>Second</li>
      <li>Third</li>
      <li>Fourth</li>
    </ol>
    <ol contenteditable="true">
      <li>First</li>
      <li>Second</li>
      <li>Third</li>
      <li>Fourth</li>
    </ol>
  </section>
</body>

这在兼容性方面似乎是最好的,因为我开始认为每个浏览器对beforeinput的响应都不同(可能没有处理程序的keydown)。我下载了一个基于Chromium的浏览器来测试它,结果与Chrome不同。

编辑:我将event.which替换为event.key,因为前者已被弃用,并且在不同的浏览器中不可靠。

剩下的问题:

  1. 如果用户重复输入~~~´´´´等,则不会 处理。
  2. 如果用户复制文本( Ctrl + C ),或者在<li>聚焦时使用其他类似的快捷方式,则事件将不情愿地发生触发,因为它听了c [感谢@trysis评论]