Как определить, когда дочерний элемент контентного DIV редактируется с клавиатуры?

Учитывая этот HTML-код:

<div contenteditable>
    ....
    <span> child-element </span>
    ....
</div>

Когда пользователь щелкает элемент SPAN (чтобы поместить в него курсор), а затем нажимает символьную клавишу на клавиатуре (для редактирования текстового содержимого элемента SPAN), появляется keydown, keypress и keyup событие будет запущено.

Однако свойство 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?


person Šime Vidas    schedule 19.07.2011    source источник


Ответы (2)


Это можно сделать с помощью 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>

Использованная литература:

person Wayne    schedule 19.07.2011
comment
@ Šime - Обновлено с помощью решения IE. Я нашел связанный пост, исследуя это. Там есть более полные ответы. - person Wayne; 20.07.2011
comment
Одно замечание: anchorNode не гарантируется, что он будет текстовым узлом во всех браузерах и во всех ситуациях. Лучше всего проверить его тип узла, чтобы убедиться, что это элемент, на всякий случай. - person Tim Down; 20.07.2011
comment
@ Тим - Да, конечно. Любой, кто использует мой ответ, действительно должен прочитать другой связанный вопрос SO, который углубляется в специфику. Единственная причина, по которой я бы сказал, что это не обман, состоит в том, что это конкретно в контексте contenteditable. - person Wayne; 20.07.2011
comment
@Tim - Кстати, рад, что ты это укрепил. Большая часть кода диапазона, который я видел в дикой природе, предполагает, что начальный и конечный узлы всегда являются текстовыми узлами, хотя в спецификации четко указано, что это не так. - person Wayne; 20.07.2011

Возможность редактирования всего div означает, что тег <span> - это не что иное, как текстовое содержимое. Если вы просто хотите, чтобы span был доступен для редактирования, установите contentEditable на самом диапазоне.

person Mrchief    schedule 19.07.2011
comment
Мне нужно, чтобы весь DIV можно было редактировать. Я использую элементы SPAN, чтобы придать определенным словам определенный стиль и поведение ... - person Šime Vidas; 19.07.2011
comment
Это неверно. Дочерние элементы по-прежнему существуют, и ими по-прежнему можно обращаться и ими можно манипулировать. Пример: jsfiddle.net/o90Lm8jr. - person T.J. Crowder; 08.07.2018