问题
have this html:
<div id="editable" contentEditable="true" >
<span contentEditable="false" >Text to delete</span>
</div>
need that the span (and all text inside) is removed with a single backspace, is it possible?
回答1:
This turned out to be more complicated than I thought. Or I've made it more complicated than it needs to be. Anyway, this should work in all the big browsers:
function getLastTextNodeIn(node) {
while (node) {
if (node.nodeType == 3) {
return node;
} else {
node = node.lastChild;
}
}
}
function isRangeAfterNode(range, node) {
var nodeRange, lastTextNode;
if (range.compareBoundaryPoints) {
nodeRange = document.createRange();
lastTextNode = getLastTextNodeIn(node);
nodeRange.selectNodeContents(lastTextNode);
nodeRange.collapse(false);
return range.compareBoundaryPoints(range.START_TO_END, nodeRange) > -1;
} else if (range.compareEndPoints) {
if (node.nodeType == 1) {
nodeRange = document.body.createTextRange();
nodeRange.moveToElementText(node);
nodeRange.collapse(false);
return range.compareEndPoints("StartToEnd", nodeRange) > -1;
} else {
return false;
}
}
}
document.getElementById("editable").onkeydown = function(evt) {
var sel, range, node, nodeToDelete, nextNode, nodeRange;
evt = evt || window.event;
if (evt.keyCode == 8) {
// Get the DOM node containing the start of the selection
if (window.getSelection && window.getSelection().getRangeAt) {
range = window.getSelection().getRangeAt(0);
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
}
if (range) {
node = this.lastChild;
while (node) {
if ( isRangeAfterNode(range, node) ) {
nodeToDelete = node;
break;
} else {
node = node.previousSibling;
}
}
if (nodeToDelete) {
this.removeChild(nodeToDelete);
}
}
return false;
}
};
回答2:
Because you want to delete the whole element, it's better to make it contenteditable="false"
so that browser won't let the contents of an element to be deleted.
Then you can use this attribute for tests in event handler as follows:
$('#editable').on('keydown', function (event) {
if (window.getSelection && event.which == 8) { // backspace
// fix backspace bug in FF
// https://bugzilla.mozilla.org/show_bug.cgi?id=685445
var selection = window.getSelection();
if (!selection.isCollapsed || !selection.rangeCount) {
return;
}
var curRange = selection.getRangeAt(selection.rangeCount - 1);
if (curRange.commonAncestorContainer.nodeType == 3 && curRange.startOffset > 0) {
// we are in child selection. The characters of the text node is being deleted
return;
}
var range = document.createRange();
if (selection.anchorNode != this) {
// selection is in character mode. expand it to the whole editable field
range.selectNodeContents(this);
range.setEndBefore(selection.anchorNode);
} else if (selection.anchorOffset > 0) {
range.setEnd(this, selection.anchorOffset);
} else {
// reached the beginning of editable field
return;
}
range.setStart(this, range.endOffset - 1);
var previousNode = range.cloneContents().lastChild;
if (previousNode && previousNode.contentEditable == 'false') {
// this is some rich content, e.g. smile. We should help the user to delete it
range.deleteContents();
event.preventDefault();
}
}
});
demo on jsfiddle
回答3:
Seems to work by default (without any javascript) in latest Chrome version (I've tested with 61.0.3163.100).
来源:https://stackoverflow.com/questions/2177958/how-to-delete-an-html-element-inside-a-div-with-attribute-contenteditable