【问题标题】:Add a node in a contenteditable "div" where the caret is (when click on a button)在插入符号所在的内容可编辑“div”中添加一个节点(单击按钮时)
【发布时间】:2014-05-12 16:43:25
【问题描述】:

我尝试在 javascript 中创建一段代码,以在插入符号所在的可内容编辑“div”中添加一个节点(“span”、“strong”...)(当我单击“按钮”时)。

我开始思考这样的代码(它不起作用,这只是一个开始):http://jsfiddle.net/Md8KX/2/

HTML:

<div id="myDiv" contenteditable="true">
    <strong>Test:</strong> This is a <strong>really</strong> good test.
</div>
<button type="button" id="myButton">Add a span</button>

CSS:

#myDiv{padding:15px;border:solid 1px #000;}

JS:

// Variable to stock the caret position
var caretPosition = 0;

// Event to get caret position on keyup and on blur
$('#myDiv').on('keyup focus', function () {
    caretPosition = getCaretPosition(this);
});

// Event to add node when click on button
$('#myButton').on('click', function (e) {
    e.preventDefault();
    addNode(this, caretPosition, '<span>Node</span>');
});

// Function to get caret position with 1 param : the editable box
var getCaretPosition = function (editableBox) {
    var position = 0;
    // TO DO : get caret position
    return position;
}

// Function to add node with 3 params : the editable box, the caret position and the node to add
var addNode = function (editableBox, caretPosition, nodeToAdd) {
    // TO DO : add node in element
}

但是我完全不知道获取光标位置然后在此时插入一个节点:) 我在 javascript 或“createTextRange”中阅读了有关“范围”属性的内容,但我不确定我是否理解,我不知道这是否是最好的方法。

您有什么想法或可以帮助我开始的曲目吗? 提前谢谢!

【问题讨论】:

  • 这是我的fiddle 类似的question。希望对您有所帮助。
  • @TimDown :效果很好,谢谢!但是还有一个问题:如果同时另一个 DOM 元素获得焦点(或者如果 contenteditable 失去焦点),该节点将不会被添加到插入符位置,而是在 div 的开头。您是否有保存插入符号位置并将其保存在变量中以避免此问题的想法?
  • 在失去焦点之前保存范围。示例:stackoverflow.com/questions/4687808/…

标签: javascript jquery contenteditable


【解决方案1】:

老帖子,我明白了。但这对我帮助很大。我在某个地方找到了这个解决方案,抱歉我不记得了,否则我会给予信任。

function pasteHtmlAtCaret(html) {
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
        // non-standard and not supported in all 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);
        }
        range.insertNode(frag);

        // Preserve the selection
        if (lastNode) {
            range = range.cloneRange();
            range.setStartAfter(lastNode);
            range.collapse(true);
            sel.removeAllRanges();
            sel.addRange(range);
        }
    }
} else if (document.selection && document.selection.type != "Control") {
    // IE < 9
    document.selection.createRange().pasteHTML(html);
}
}

【讨论】:

    【解决方案2】:

    我为此创建了一个工作示例,虽然并不完美,但我希望它可以作为您想要实现的目标的基础。可以在这里找到:http://jsbin.com/jociy/2

    这是源代码,不言自明:

    $(document).ready(function(){
    
      // helper function credit to http://stackoverflow.com/questions/3972014/get-caret-position-in-contenteditable-div
      function getCaretPosition(editableDiv) {
        var caretPos = 0, containerEl = null, sel, range;
        if (window.getSelection) {
            sel = window.getSelection();
            if (sel.rangeCount) {
                range = sel.getRangeAt(0);
                if (range.commonAncestorContainer.parentNode == editableDiv) {
                    caretPos = range.endOffset;
                }
            }
        } else if (document.selection && document.selection.createRange) {
            range = document.selection.createRange();
            if (range.parentElement() == editableDiv) {
                var tempEl = document.createElement("span");
                editableDiv.insertBefore(tempEl, editableDiv.firstChild);
                var tempRange = range.duplicate();
                tempRange.moveToElementText(tempEl);
                tempRange.setEndPoint("EndToEnd", range);
                caretPos = tempRange.text.length;
            }
        }
        return caretPos;
      }
    
      // listener will keep track of caret position
      var position = 0;
      $('#myDiv').keyup(function() { 
    
         position = getCaretPosition(this);
    
      });
    
      // the special span element to insert
      var mySpan = "<span class='mySpan'>Yes!</span>";
    
      $("#myButton").on("click", function(){
    
        // sorry about this, this can and should be refactored
        var data1 = $("#myDiv").text().slice(0, position);
        var data2 = $("#myDiv").text().slice(position,$("#myDiv").text().length);
    
        $("#myDiv").html("<span>" + data1 + mySpan + data2 + "</span>");
    
      });
    
    
    });
    

    此示例的 HTML 元素:

      <div id="myDiv" class="yellow foo" contenteditable="true">Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. Summus brains sit , morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris.</div>
    
      <button type="button" id="myButton">Add SPAN</button>
    

    如果您愿意,可以选择一些样式:

    .foo {
      font-family: arial, sans-serif;
      margin: 10px;
      padding: 25px;
      opacity: 0.6;
    }
    .yellow {
      background-color: yellow;
      color: #000;
    }
    button {
      padding: 20px;
      margin-left: 10px;
      border: none;
      background-color: #ccc;
      color: #fff;
      font-weight: bold;
      text-shadow: 1px 1px 0px #888;
      text-transform: uppercase;
      cursor: pointer;
    }
    button:hover {
      opacity: 0.6;
    }
    .mySpan {
     background-color: red;
     color: yellow; 
    }
    

    希望这会有所帮助!

    【讨论】:

    • 不幸的是,这不是我需要的 :) 在您的示例中,您使用了不允许多个节点同时在 contenteditable 中的“text ()”属性。我认为我们应该使用“html()”属性和属性“childNodes”,但我不知道如何:) 但是谢谢你的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 2018-06-16
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多