【问题标题】:Is it possible remove span element node around text node without interrupting the cursor?是否可以在不中断光标的情况下删除文本节点周围的 span 元素节点?
【发布时间】:2022-02-14 09:23:38
【问题描述】:

在以下结构中:

<div contenteditable="true">
    <span class="some-class">Hello</span>
    World <!-- no span here -->
    <span class="some-other-class">and good bye!</span>
</div>

是否可以在不中断contenteditabledivdiv中的光标位置的情况下删除选定的span元素,但不能删除文本节点?

所以即使光标在 span 内,也保持相同的文本内容,只是移除它周围的 span 元素

例如,如果some-class 的样式是红色文本颜色并且我将光标放在单词“Hello”内的某个位置,那么我希望样式消失并删除包装span

【问题讨论】:

    标签: javascript html


    【解决方案1】:

    给你!

    <div contenteditable="true">
        <span class="some-class" style="color: red">Hello</span>
        <span class="some-class" style="color: blue">world</span>
        <span class="some-other-class" style="color: orange">and good bye!</span>
        <span style="color: green">test</span>
    </div>
    
    <script>
        const div = document.querySelector('div');
    
        const getSelection = () => {
            let offset = 0;
            const selection = window.getSelection();
            const range = selection.getRangeAt(0);
            let start = range.startOffset;
            let end = range.endOffset;
    
            if (selection.baseNode.parentNode.hasChildNodes()) {
                for (const node of selection.baseNode.parentNode.childNodes) {
                    const cnode = node;
                    if (cnode.nodeType == document.TEXT_NODE && !(offset + cnode.length > start)) {
                        offset = offset + cnode.length;
                    }
                    if (cnode.nodeType == document.ELEMENT_NODE && !(offset + cnode.textContent.length > start)) {
                        offset = offset + cnode.textContent.length;
                    }
                }
            }
    
            start = start + offset;
            end = end + offset;
    
            return { start, end };
        };
    
        const removeSpan = ({ target, currentTarget: { selectionStart } }) => {
            // Get our selection points for within our span element
            const { start, end } = getSelection();
    
            // Only run this logic for span elements
            if (target.tagName === 'SPAN') {
                // Create new text node from our span's innerText
                const text = document.createTextNode(target.innerText + ' ');
    
                // Replace span with just the text
                target.replaceWith(text);
    
                // Create a range and set selection range back to what it was to not affect cursor
                const range = document.createRange();
                range.setStart(text, start);
                range.setEnd(text, end);
    
                const selection = window.getSelection();
                selection.removeAllRanges();
                selection.addRange(range);
            }
        };
    
        div.addEventListener('click', removeSpan);
    </script>

    【讨论】:

    • 看起来不错。但是我遇到了一个边界情况:点击单词test的某处,然后点击and good bye!的某处,然后将光标放在单词world的末尾(在字母d之后)-有一个@ 987654326@。知道为什么吗?
    • @B.DLiroy 我没有遇到与您的测试用例相同的错误,但我以前遇到过。原因是我们有时出于某种原因将文本节点内选择范围的起点设置为大于文本节点的长度。据我所知,此错误不会影响功能。也许你可以修复它,因为这段代码已经是你想要的 99% :)
    猜你喜欢
    • 2023-04-03
    • 2021-05-10
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 2019-11-27
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多