如何在contenteditable中跟踪插入符/光标?

时间:2012-07-11 22:33:58

标签: javascript contenteditable

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

我正在听click,keydown,keyup。 (按键当然甚至不会触发箭头键或ctrl-x之类的东西。)

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

这一定是可能的,因为CKeditor之类的东西能够做到这一点。任何提示?

4 个答案:

答案 0 :(得分:10)

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

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

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

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

不幸的是,选择处理是目前wysiwygs世界中最差的任务。它在所有新旧浏览器中都如此破碎。我上面链接的文件中超过75%的LOC是黑客和技巧。这完全是疯狂的。

答案 1 :(得分:5)

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

然而,在IE中(一直回到至少5.5)和最近的WebKit,只要选择发生变化,就会在文档上触发selectionchange event

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

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

答案 2 :(得分:0)

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

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事件,这实际上是另一个痛苦的事情。

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

答案 3 :(得分:0)

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

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

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