如何检测使用键盘编辑contenteditable DIV的子元素?

12
给定这段HTML代码:
<div contenteditable>
    ....
    <span> child-element </span>
    ....
</div>

当用户点击SPAN元素(以使插入符在其中),然后按下键盘上的字符键(以编辑SPAN元素的文本内容)时,将触发一系列事件,包括 keydownkeypresskeyup

然而,这些相应事件对象的target属性不是SPAN元素,而是DIV元素本身。

演示:(同时也可以在 jsFiddle上查看)

$('div').keydown(function(e) {
    alert( e.target.nodeName );
});
div { border:2px solid red; padding:10px; margin:10px; }
span { background-color:yellow; }
<div contenteditable>
    BEFORE
    <span>SPAN</span>
    AFTER
</div>

<p>
    Click on the yellow SPAN element (to place the caret inside it), and then press a character key (to change the text-content of the SPAN element). The alert-box shows that the event-target is the DIV element, not the SPAN element...
</p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

我该如何确定按键事件是否发生在 SPAN 元素内部?

2个回答

17

这可以使用选择 API 完成:

$('div').keydown(function(e) {
    if (document.selection) {
        alert(document.selection.createRange().parentElement().tagName); // IE
    } else {
        // everyone else
        alert(window.getSelection().anchorNode.parentNode.tagName); 
    }
});

注意:上述示例过于简单。请参见下面链接的SO帖子,获取完整的选择问题解决方案。

演示(也可在jsFiddle上查看):

$('div').keydown(function(e) {
    if (document.selection)
        alert(document.selection.createRange().parentElement().tagName); // IE
    else
        alert(window.getSelection().anchorNode.parentNode.tagName); // everyone else
});
div { border:2px solid red; padding:10px; margin:10px; }
span { background-color:yellow; }
<div contenteditable>
    BEFORE
    <span>SPAN</span>
    AFTER
</div>

<p>
    Click on the yellow SPAN element (to place the caret inside it), and then press a character key (to change the text-content of the SPAN element). The alert-box shows that the event-target is the DIV element, not the SPAN element...
</p>
<div id="stuff"/>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

参考资料:


@Šime - 已更新IE解决方案。我在研究这个问题时找到了链接的帖子。那里有更完整的答案。 - Wayne
一个要点:在所有浏览器和所有情况下,anchorNode不能保证是一个文本节点。最好检查它的节点类型,看看它是否是一个元素,以确保安全。 - Tim Down
@Tim - 是的,绝对是这样。任何使用我的答案的人都需要阅读其他链接的SO问题,以了解具体情况。我之所以说这不是重复问题的唯一原因是因为它是在特定的“contenteditable”上下文中。 - Wayne
@Tim - 顺便说一句,很高兴你加强了这一点。我在野外看到的大多数范围代码都假设开始和结束节点始终是文本节点,尽管规范明确指出它们不是。 - Wayne

0
使整个
可编辑意味着标签仅仅是文本内容。如果您只想让可编辑,请在本身上设置contentEditable属性。

我需要整个DIV可编辑。我使用SPAN元素为某些单词提供特定的样式和行为... - Šime Vidas
这是不正确的。子元素仍然存在,可以继续访问和操作。示例:http://jsfiddle.net/o90Lm8jr/ - T.J. Crowder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接