如何在具有contentEditable属性的div中删除HTML元素?

7

have this html:

<div id="editable" contentEditable="true"  >
    <span contentEditable="false" >Text to delete</span>
</div>

需要使用一个单一的退格键删除 span 元素(以及其中的所有文本),这是否可能?

请您提供更多信息,例如当插入符号处于文本节点中间或可编辑区域的起始位置时,用户按下退格键时应该发生什么事件。 - Tim Down
2个回答

12

结果比我想象的更加复杂。或者我把它弄得比必要的更加复杂了。无论如何,在所有主流浏览器中都应该可以正常工作:

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;
    }
};

不,我只需要删除文本光标左侧的元素 | - byterussian
如何通过使用Enter键按下添加span并使用退格键删除span,使此代码更具动态性?如果您能帮助我就太好了。 - Basbous
这在Chrome中可以工作,但在Firefox中无法工作。是否有Firefox浏览器中与Node相关的问题?我需要帮助,请查看附加链接 - Dhananjay C
Dhananjay C:您的代码没有错误,可以正常运行 - http://jsfiddle.net/dpx4f9hm/ - Kelly

11
因为您想要删除整个元素,所以最好将其设置为contenteditable="false",这样浏览器就不会允许删除元素的内容。
然后,您可以在事件处理程序中使用此属性进行测试,如下所示:
$('#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();
        }
    }
});

在 jsfiddle 上的演示


完美解决了我的问题。 - Saravanan
哇...这是一个惊人的简单解决方案!将我想要删除的div的contenteditable设置为false,让我一次性删除了该div! - Ayudh
非常好的答案!非常感谢!不过我有一个问题。你说的“选择处于字符模式”是什么意思?我也似乎无法触发那个事件。/K - Kermit
我成功地通过删除一个换行符来触发“选择处于字符模式”部分。/K - Kermit

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