【问题标题】:How to track caret/cursor in contenteditable?如何在 contenteditable 中跟踪插入符号/光标?
【发布时间】:2012-07-26 21:06:22
【问题描述】:

我想在 contenteditable 中跟踪插入符号/光标的移动。不过,我不确定最好的方法是什么。

我目前正在监听 click、keydown、keyup。 (当然,对于箭头键或 ctrl-x 之类的东西,keypress 甚至不会触发。)

虽然单击工作正常,但 keydown 的问题在于它在插入符号实际移动之前被触发,因此当我查询当前文档选择范围时,我得到的是旧位置而不是新位置。但是,如果我依靠 keyup 来获取更新的位置,它触发得太晚了:一旦按下键,插入符号就会移动,但在任意时间之后释放键。

这一定是可能的,因为像 CKeditor 这样的东西能够做到这一点。有什么提示吗?

【问题讨论】:

  • 这很奇怪,这正是我今天的工作!
  • @MaxArt 那么你应该为这个问题投票/加注星标:)
  • 你说得对,我马上就做到了。顺便说一句,我正在回答我的结果。
  • 为什么你认为 keyup 可能为时已晚?中间会发生什么?
  • @Bergi 太晚了,因为一旦按下键,插入符号就会移动 - 键会在任意时间后释放。澄清了我的问题。

标签: javascript contenteditable


【解决方案1】:

很高兴看到人们在谈论 CKEditor :)。我是它的开发人员之一,我没有在选择方面做太多工作,但我会尽力提供帮助。

我知道我们有一个内部selectionChange 事件。那么我们什么时候检查它是否改变了呢? ... ...每 200 毫秒至少一次 :) 见:

http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/selection/plugin.js#L39

每次我们知道选择可能已更改时,我们也会检查它(例如,通过 API 或在 keyup/mouseup 或在本机 selectionchange 上 - http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/selection/plugin.js#L554)。所以......几乎所有时间:) AFAIK 我们做了一些技巧,所以它不会烧毁你的 CPU,但它仍然很重。但是,如果我们这样做了,那么它是唯一可能让它工作得很好的方法。

不幸的是,选择处理是目前所见即所得世界中最糟糕的任务。它在所有旧浏览器和新浏览器中都被破坏了。我上面链接的文件中超过 75% 的 LOC 是黑客和技巧。这简直是​​疯了。

【讨论】:

    【解决方案2】:

    在 Mozilla 和 Opera 中,处理按键和鼠标事件是您唯一的选择。它不仅繁琐,而且并不涵盖所有情况:可以通过编辑和上下文菜单(例如,通过全选)更改选择。为了解决这个问题,您还需要添加某种对选择对象的轮询。

    但是,在 IE(一直到至少 5.5)和最近的 WebKit 中,只要选择更改,就会在文档上触发 selectionchange event

    document.onselectionchange = function() {
        alert("Selection changed!");
    };
    

    Mozilla 将来有机会支持它:https://bugzilla.mozilla.org/show_bug.cgi?id=571294

    【讨论】:

      【解决方案3】:

      由于您所说的原因,这不是一件容易的事。我想出了一些像这样的东西:

      var caretInterval, caretOffset;
      document.addEventListener("keydown", function(e) {
          if (!e.target.contentEditable || caretInterval) return;
          if (e.keyCode !== 37 && e.keyCode !== 39) // Left and right
              return;
          var sel = getSelection();
          caretInterval = setInterval(function() {
              if (sel.type === "Caret") caretOffset = sel.baseOffset;
          }, 50);
      });
      document.addEventListener("keyup", function(e) {
          if (e.keyCode !== 37 && e.keyCode !== 39) // Left and right
              return;
          clearInterval(caretInterval);
          caretInverval = null;
          var sel = getSelection();
          if (sel.type === "Caret") caretOffset = sel.baseOffset;
      });
      

      如果有人试图同时按左键和右键,可能会出现一个小问题。对于 ctrl-X 和 ctrl-V,您应该捕获 cutpaste 事件,这实际上是另一个麻烦。

      最后,我决定不值得为我的目的付出努力。也许你有不同的需求。

      【讨论】:

        【解决方案4】:

        WRT 捕获事件选择被更新:我只是将我的处理函数包装在超时中:

        editor.onkeydown = function() {
          window.setTimeout( function(){
            // Your handler code here
          }, 0 );
        };
        

        这会将您的处理程序注册为尽快在浏览器的事件循环中执行,但要在处理当前(例如单击)事件之后。但是,如果您有其他脚本修改内容,请注意可能的比赛;不能保证您的超时是下一个要运行的。

        【讨论】:

          猜你喜欢
          • 2012-10-15
          • 2013-04-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多