contenteditable div - 划分span标签 - 避免嵌套

时间:2018-02-24 13:31:27

标签: javascript jquery html nested contenteditable

我正在使用contenteditable进行打字工具。当用户键入一些文本时,我将其插入span标签并将其添加到主div;结果是这样的:

<span style="color: black;">hello</span>

如果用户将插入符号放在单词“hello”中并开始用不同的颜色键入,结果将是:

<span style="color: black;">he<span style="color: red;">new text</span>llo</span>

我真正希望实现的目标是:

<span style="color: black;">he</span>
<span style="color: red;">new text</span>
<span style="color: black;">llo</span>

我想避免使用嵌套的span元素。 目前我使用此过程添加span标记:

var sel = window.getSelection();
var range = sel.getRangeAt(0);

var spanTag = "<span id='newSpan' style='color: " + currentColor + "'>00000</span>"; // &#8203;
var documentFragment = range.createContextualFragment(spanTag);

range.insertNode(documentFragment);

var dummySpan = document.getElementById("newSpan");

range.setStart(dummySpan, 1);
range.setEnd(dummySpan, 1);

sel.removeAllRanges();
sel.addRange(range);

$("#newSpan").removeAttr("id");
dummySpan.innerHTML = "";

我只是想知道我是否遗漏了一些jquery或javascript函数,这些函数可以帮助您轻松实现这一目标。

1 个答案:

答案 0 :(得分:0)

最后我用这个功能做了。基本上我将当前标签文本的一半分成了插入位置,创建了两个单独的标签,每个标签都有一半的文本,在中间创建一个当前颜色的新标签,并将插入符号放入其中。

function typeInKanji() {

    var sel = window.getSelection();
    var range = sel.getRangeAt(0);

    var currentNode = sel.anchorNode;   
    var elementNode = getSelectionElement();

    var caretPosition = getCaretCharacterOffsetWithin(elementNode);

    if (elementNode.tagName == "SPAN") { 

        if (elementNode.style.color == currentColor) {

            console.log("span of same color, do nothing and keep typing");

        } else {

            console.log("span of a different color, split it");

            var tagText = elementNode.innerText;

            console.log("text: " + tagText + " position: " + caretPosition);

            var firstHalf = tagText.substr(0, caretPosition);
            var secondHalf = tagText.replace(firstHalf, "");

            // remove the old element with all the text
            $(elementNode).remove();

            var firstTag = "<span style='color: " + elementNode.style.color + "'>" + firstHalf + "</span>"
            var secondTag = "<span style='color: " + elementNode.style.color + "'>" + secondHalf + "</span>"
            var middleTag = "<span id='middleTag' style='color: " + currentColor + "'>00</span>"

            var firstFrag = range.createContextualFragment(firstTag);
            var secondFrag = range.createContextualFragment(secondTag);
            var middleFrag = range.createContextualFragment(middleTag);

            range.insertNode(secondFrag);
            range.insertNode(middleFrag);
            range.insertNode(firstFrag);

            var getMiddleTag = document.getElementById("middleTag");

            console.log(getMiddleTag);

            range.setStart(getMiddleTag, 0);
            range.setEnd(getMiddleTag, 0);

            sel.removeAllRanges();
            sel.addRange(range);

            $("#middleTag").removeAttr("id");
            getMiddleTag.innerHTML = "";

        }


    } else {

        // if there is not SPAN tag create one
        insertTag("<span id='newSpan' style='color: " + currentColor + "'>00</span>");

        var dummySpan = document.getElementById("newSpan");

        range.setStart(dummySpan, 1);
        range.setEnd(dummySpan, 1);

        sel.removeAllRanges();
        sel.addRange(range);

        $("#newSpan").removeAttr("id");
        dummySpan.innerHTML = "";

    }

    typeKanjiNow = false;

}

这里是我使用的另外两个函数:

function getCaretCharacterOffsetWithin(element) {

    var caretOffset = 0;
    var doc = element.ownerDocument || element.document;
    var win = doc.defaultView || doc.parentWindow;
    var sel;

    if (typeof win.getSelection != "undefined") {

        sel = win.getSelection();

        if (sel.rangeCount > 0) {

            var range = win.getSelection().getRangeAt(0);
            var preCaretRange = range.cloneRange();
            preCaretRange.selectNodeContents(element);
            preCaretRange.setEnd(range.endContainer, range.endOffset);
            caretOffset = preCaretRange.toString().length;

        }

    } else if ( (sel = doc.selection) && sel.type != "Control") {

        var textRange = sel.createRange();
        var preCaretTextRange = doc.body.createTextRange();
        preCaretTextRange.moveToElementText(element);
        preCaretTextRange.setEndPoint("EndToEnd", textRange);
        caretOffset = preCaretTextRange.text.length;

    }

    return caretOffset;

}

function insertTag(tag) {

    var sel = window.getSelection();
    var range = sel.getRangeAt(0);

    var currentNode = sel.anchorNode;   

    var documentFragment = range.createContextualFragment(tag);
    range.insertNode(documentFragment);

}