如何获取正在编辑的元素?

How do I get the element being edited?

我正在开发一个网络应用程序,我遇到了 JavaScript 的问题。

以下是导致问题的 HTML 的简化版本。我有一些嵌套的 contenteditable divs (我用占位符文本替换了真实内容):

<div contenteditable="true" id="div1">
    text
    <div contenteditable="inherit" id="div2">
        text
        <div contenteditable="inherit" id="div3">
            text
        </div>
        text
    </div>
    text
</div>

我想通过JavaScript,获取选中的(被用户编辑的)元素,但是到目前为止我还没有找到方法(成功)。


我尝试过的方法以及为什么它不起作用:

我试过使用 document.activeElement,它应该 return 哪个元素处于焦点。通常这可行,但在处理嵌套的 contenteditable 元素时不会产生预期的结果。它不是 return 正在被用户编辑的元素,而是 return 最高的 contenteditable 祖先。

例如,如果 div2 被 selected/being 编辑,document.activeElement returns div1。如果 div3 被 selected/being 编辑,document.activeElement 也会 returns div1.

所以我想 document.activeElement 不是正确的方法。


如何获取正在编辑的最具体的元素,而不是其最高的 contenteditable 祖先元素?

在这个 fiddle 中似乎对我来说很好用: http://jsfiddle.net/dgrundel/huL4sjem/

我正在使用此代码检查:

<div contenteditable="true" class="edit">
    This is editable.
</div>

<script>
    $('.edit').on('click', function(){
        console.log(document.activeElement);
    });
</script>

当我单击可编辑元素时,控制台会获取记录到其中的 div 的副本。

$('#edit').on('click', function() {
  // this is the innermost *node*
  var an = window.getSelection().anchorNode;
  // this is the innermost *element*
  var ae = an;
  while (!( ae instanceof Element ))
    ae = ae.parentElement;
  $('#an').text(an.nodeValue);
  $('#ae').text(ae.outerHTML);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div contenteditable="true" id="edit">
  This is editable. <span>What?</span> <em>How about this?</em>
</div>
<br/>
Active Node:<br/>
<pre id="an">Nothing</pre>
<br/>
Active Element:<br/>
<pre id="ae">Nothing</pre>
<br/>

给你。点击"Run snippet."玩得开心。

下面的示例显示了使用 input 事件的行为。这将模仿突变观察者的行为。

$('#edit').on('input', function() {
  // this is the innermost *node*
  var an = window.getSelection().anchorNode;
  // this is the innermost *element*
  var ae = an;
  while (!( ae instanceof Element ))
    ae = ae.parentElement;
  $('#an').text(an.nodeValue);
  $('#ae').text(ae.outerHTML);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div contenteditable="true" id="edit">
  This is editable. <span>What?</span> <em>How about this?</em>
</div>
<br/>
Active Node:<br/>
<pre id="an">Nothing</pre>
<br/>
Active Element:<br/>
<pre id="ae">Nothing</pre>
<br/>

下面的示例显示了使用 keydownkeyup 事件的行为。这将捕获非修改按键,如箭头和修改键。

$('#edit').on('keydown keyup', function() {
  // this is the innermost *node*
  var an = window.getSelection().anchorNode;
  // this is the innermost *element*
  var ae = an;
  while (!( ae instanceof Element ))
    ae = ae.parentElement;
  $('#an').text(an.nodeValue);
  $('#ae').text(ae.outerHTML);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div contenteditable="true" id="edit">
  This is editable. <span>What?</span> <em>How about this?</em>
</div>
<br/>
Active Node:<br/>
<pre id="an">Nothing</pre>
<br/>
Active Element:<br/>
<pre id="ae">Nothing</pre>
<br/>

我通过在插入符位置插入一个虚拟元素并找到它的直接父元素来做到这一点。

function getActiveDiv() {
    var sel = window.getSelection();
    var range = sel.getRangeAt(0);
    var node = document.createElement('span');
    range.insertNode(node);
    range = range.cloneRange();
    range.selectNodeContents(node);
    range.collapse(false);
    sel.removeAllRanges();
    sel.addRange(range);
    var activeDiv = node.parentNode;
    node.parentNode.removeChild(node);
    return activeDiv;
}

我在 fiddle 上做了一个例子: https://jsfiddle.net/shhe05cj/4/

我运行它在绑定到相关 div 的每个按键事件上。

我基于另一个线程做了类似的事情:Set caret position right after the inserted element in a contentEditable div

这对我有用:

   $(document).click(function(event) {
            console.log(event.target);
        });