【问题标题】:How can split element (inside editable div) from the cursor position into two parts, Then insert a custom element between it?如何将元素(在可编辑的div内)从光标位置分成两部分,然后在它之间插入一个自定义元素?
【发布时间】:2020-10-15 00:13:21
【问题描述】:

我需要将光标位置的元素(在可编辑的div内)分成两部分,然后在其之间插入一个自定义元素。

在进行更改之前: (竖线“|”表示光标的位置。我用“|”表示光标所在的位置给你。但实际上,这个字符在文本中是不存在的。)

<div contenteditable="true">
  <span style="font-size='14px'">this is | a test</span>

  <p>other paragraphs .....</p>
</div>

修改后:

<div contenteditable="true">
  <span style="font-size:'14px'">this is </span><span style="font-size:'16px'">new text|</span><span style="font-size:'14px'">a test</span>

<p>other paragraphs .....</p>
</div>

需要注意的是,修改后,光标必须插入到新的自定义元素最后一个字母之后。

我试了一下,但是:

  let sel = window.getSelection();
  let range = sel.getRangeAt(0);
  if (range.startContainer.parentNode.nodeName === 'SPAN') {
    let sel, range, cloneNode1, cloneNode2, cloneText, allContents, contentsBeforeCursor, contentsAfterCursor, newNode
    sel = window.getSelection();
    range = document.createRange();
    range.selectNode(sel.anchorNode);
    cloneNode1 = range.commonAncestorContainer.cloneNode();
    cloneNode2 = cloneNode1.cloneNode();
    cloneText = range.cloneContents();

    allContents = cloneText.textContent;
    contentsBeforeCursor = allContents.substring(0, sel.anchorOffset);
    contentsAfterCursor = allContents.substring(sel.anchorOffset, allContents.length);
    cloneNode1.textContent = contentsBeforeCursor
    cloneNode2.textContent = contentsAfterCursor
    newNode = document.createElement('SPAN');
    for (let i = 0; i < cloneNode1.attributes.length; i++) {
      let attr = cloneNode1.attributes.item(i);
      newNode.setAttribute(attr.nodeName, attr.nodeValue);
    }
    newNode.style.fontSize = '13px';

    range.selectNode(sel.anchorNode.parentNode);
    range.deleteContents();
    range.insertNode(cloneNode1)
    range.insertNode(newNode)
    range.insertNode(cloneNode2)
    newNode.focuse();

https://jsfiddle.net/nekooee/0h8zcfv4/43/

这是为了改变 SPAN 中间的字体。 CKEditor 也是如此。

【问题讨论】:

  • @ggorlen 我编辑了我的问题并添加了最少的尝试代码。谢谢
  • 获取 div 的innerHTML。说:var innerHTML=div.innerHTML。然后:innerHTML.split("|").join("element to be inserted here")。然后:div.innerHTML=innerHTML。或者,一行:div.innerHTML=div.innerHTML.split("|").join("element to be inserted here")
  • 如果要拆分周围的元素,则需要获取打开和关闭部分并复制它们:关闭、插入、打开。使用split & join.indexOf...
  • @iAmOren 谢谢。您的第一个代码无法使用,因为您已经考虑了所有 div 内容。那里还有其他元素。只能根据光标获取元素。您发表的第二条评论是正确的。但是不知道怎么写?
  • @iAmOren 我用了“|”显示光标所在的位置。但实际上,文本中并不存在这个字符。请帮帮我。

标签: javascript html


【解决方案1】:

我找到了答案。代码应该这样写:

let sel = window.getSelection();
let range = sel.getRangeAt(0);
if (range.startContainer.parentNode.nodeName === 'SPAN') {
    let newNode = document.createElement('SPAN');
   
    let cloneNode1, cloneNode2, cloneText, allContents, contentsBeforeCursor, contentsAfterCursor;
    const anchorOffset = sel.anchorOffset
    range.selectNode(sel.anchorNode);
    cloneNode1 = range.commonAncestorContainer.cloneNode();
    cloneNode2 = cloneNode1.cloneNode();
    cloneText = range.cloneContents();

    allContents = cloneText.textContent;
    contentsBeforeCursor = allContents.substring(0, anchorOffset);
    contentsAfterCursor = allContents.substring(anchorOffset, allContents.length);

    cloneNode1.textContent = contentsBeforeCursor;
    cloneNode2.textContent = contentsAfterCursor;

    for (let i = 0; i < cloneNode1.attributes.length; i++) {
        let attr = cloneNode1.attributes.item(i);
        newNode.setAttribute(attr.nodeName, attr.nodeValue);
    }
    newNode.style.fontSize = '13px';

    range.selectNode(sel.anchorNode);
    range.deleteContents();
    range.insertNode(cloneNode1);
    range.setStartAfter(cloneNode1);
    range.insertNode(cloneNode2)

    range.setStartAfter(cloneNode1);
    range.insertNode(newNode);
    const textNode = document.createTextNode('\u00A0');
    range.setStart(newNode, 0);
    range.insertNode(textNode);
    sel.removeAllRanges();
    range.selectNodeContents(newNode);
    sel.addRange(range);
}

【讨论】:

    【解决方案2】:

    就像我在评论 isn't this what you want 中所说的那样?

    它甚至有和你一样的 HTML 标记。

    您的 HTML 标记也完全错误:

    <span style="font-size='14px'">
    

    应该是:

     <span style="font-size:14px">
    

    示例中的每个样式属性也是如此。

    function pasteHtmlAtCaret(html, selectPastedContent) {
        var sel, range;
        if (window.getSelection) {
            // IE9 and non-IE
            sel = window.getSelection();
            if (sel.getRangeAt && sel.rangeCount) {
                range = sel.getRangeAt(0);
                range.deleteContents();
    
                // Range.createContextualFragment() would be useful here but is
                // only relatively recently standardized and is not supported in
                // some browsers (IE9, for one)
                var el = document.createElement("div");
                el.innerHTML = html;
                var frag = document.createDocumentFragment(), node, lastNode;
                while ( (node = el.firstChild) ) {
                    lastNode = frag.appendChild(node);
                }
                var firstNode = frag.firstChild;
                range.insertNode(frag);
    
                // Preserve the selection
              /*
                if (lastNode) {
                    range = range.cloneRange();
                    range.setStartAfter(lastNode);
                    if (selectPastedContent) {
                        range.setStartBefore(firstNode);
                    } else {
                        range.collapse(true);
                    }
                    sel.removeAllRanges();
                    sel.addRange(range);
                }*/
            }
        } else if ( (sel = document.selection) && sel.type != "Control") {
            // IE < 9
            var originalRange = sel.createRange();
            originalRange.collapse(true);
            sel.createRange().pasteHTML(html);
            if (selectPastedContent) {
                range = sel.createRange();
                range.setEndPoint("StartToStart", originalRange);
                range.select();
            }
        }
    }
    
    function test()
        {
            var input = '<span style="font-size:25px;color:red"> new text </span>';
            //document.getElementById("myDiv").focus();
            pasteHtmlAtCaret(input, false);
        }
    <div contenteditable="true">
      <span style="font-size:14px">this is a test</span>
    
      <p>other paragraphs .....</p>
      
    <button type="button" onclick="test()" unselectable="on">Test</button>
    </div>

    【讨论】:

    • 首先,非常感谢。我认为有问题。因为“新文本”被添加到按钮!另外,之前的 span 也没有分成两部分。
    • 我从 div 中移动了按钮,现在“新文本”将添加到光标位置。但不是删除前一个跨度并创建 3 个新跨度,而是在前一个跨度内创建一个新跨度。请参阅问题中的“进行更改后”部分。你的代码:jsfiddle.net/nekooee/L3srva9u/3
    • 如果我只想插入我的 HTML,这非常容易。比你写的更短更简单。但是,旧的 SPAN 必须拆分并在它们之间插入 HTML。
    • @nekooee 你如何在“我的”跨度中添加附加: 在 biginng 和 最后,这将“拆分”它。它的基本 html 操作。
    • 我尝试为输入 html 添加 ' 新文本 ' 但拆分不正确。看这个示例代码:jsfiddle.net/nekooee/L3srva9u/11
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多