【问题标题】:Set caret position right after the inserted element in a contentEditable div在 contentEditable div 中插入的元素之后设置插入符号位置
【发布时间】:2011-06-17 14:44:12
【问题描述】:

我正在向 contentEditable div 中插入一个元素,但浏览器将光标的位置设置在插入的元素之前。是否可以在插入元素之后设置光标,以便用户继续输入而无需重新调整光标位置?

【问题讨论】:

  • 这不能回答我的问题。我可以在插入符号位置插入元素,但我需要将插入符号放在插入元素之后。
  • 您是否尝试过在插入字符串后模拟键盘事件,例如键盘上的“end”(keycode #35)键。
  • 由于某种原因不起作用(在 Google Chrome 上测试)
  • 虽然可以模拟按键事件,但一般无法模拟按键事件的实际 UI 效果。

标签: javascript contenteditable


【解决方案1】:

下面的函数会做到这一点。 DOM Level 2 Range 对象在大多数浏览器中使这很容易。在 IE 中,您需要在要插入的节点之后插入一个标记元素,将选择移至该节点,然后将其删除。

现场示例:http://jsfiddle.net/timdown/4N4ZD/

代码:

function insertNodeAtCaret(node) {
    if (typeof window.getSelection != "undefined") {
        var sel = window.getSelection();
        if (sel.rangeCount) {
            var range = sel.getRangeAt(0);
            range.collapse(false);
            range.insertNode(node);
            range = range.cloneRange();
            range.selectNodeContents(node);
            range.collapse(false);
            sel.removeAllRanges();
            sel.addRange(range);
        }
    } else if (typeof document.selection != "undefined" && document.selection.type != "Control") {
        var html = (node.nodeType == 1) ? node.outerHTML : node.data;
        var id = "marker_" + ("" + Math.random()).slice(2);
        html += '<span id="' + id + '"></span>';
        var textRange = document.selection.createRange();
        textRange.collapse(false);
        textRange.pasteHTML(html);
        var markerSpan = document.getElementById(id);
        textRange.moveToElementText(markerSpan);
        textRange.select();
        markerSpan.parentNode.removeChild(markerSpan);
    }
}

或者,您可以使用我的Rangy library。那里的等效代码将是

function insertNodeAtCaret(node) {
    var sel = rangy.getSelection();
    if (sel.rangeCount) {
        var range = sel.getRangeAt(0);
        range.collapse(false);
        range.insertNode(node);
        range.collapseAfter(node);
        sel.setSingleRange(range);
    }
}

【讨论】:

  • 嘿。这很有趣:“DOM Level 2 Range 对象在大多数浏览器中使这变得容易。”三天来一直在尝试各种排列,但收效甚微。 (我知道,这不是一个有用的评论,但不得不说)
  • @eon: :) 也许我应该这样说:“与 IE
  • 似乎只适用于文本节点。尝试给它一个跨度元素,光标在跨度之前结束??
  • 这个也适用于非文本元素(至少是一个空的 li)stackoverflow.com/questions/9828623/…
【解决方案2】:

如果您要插入一个空的 div、p 或 span,我相信在新创建的元素内需要有“东西”才能抓取范围 - 并将插入符号放入其中。

这是我的 hack,在 Chrome 中似乎可以正常工作。这个想法只是在元素中放置一个临时字符串,然后在插入符号出现后将其删除。

// Get the selection and range
var idoc = document; // (In my case it's an iframe document)
var sel = idoc.getSelection();
var range = sel.getRangeAt(0);

// Create a node to insert
var p = idoc.createElement("p"); // Could be a div, span or whatever

// Add "something" to the node.
var temp = idoc.createTextNode("anything");
p.appendChild(temp);
// -- or --
//p.innerHTML = "anything";

// Do the magic (what rangy showed above)
range.collapse(false);
range.insertNode( p );
range = range.cloneRange();
range.selectNodeContents(p);
range.collapse(false);
sel.removeAllRanges();
sel.addRange(range);

// Clear the non
p.removeChild(p.firstChild);
// -- or --
//p.innerHTML = "";

【讨论】:

    【解决方案3】:

    这就是在 VueJS 上下文中使用 Rangy 对我有用的方法。

    // When the user clicks the button to open the popup to enter
    // the URL, run this function to save the location of the user's
    // selection and the selected text.
    newSaveSel: function() {
      if (this.savedSel) {
        rangy.removeMarkers(this.savedSel);
      }
      // Save the location of the selected text
      this.savedSel = rangy.saveSelection();
      // Save the selected text
      this.savedSelText = rangy.getSelection().toString();
      this.showLinkPopup = true;
      console.log('newSavedSel', this.savedSel);
    },
    surroundRange: function() {
      // Restore the user's selected text. This is necessary since
      // the selection is lost when the user stars entering text.
      if (this.savedSel) {
        rangy.restoreSelection(this.savedSel, true);
        this.savedSel = null;
      }
      // Surround the selected text with the anchor element
      var sel = rangy.getSelection();
    
      var range = sel.rangeCount ? sel.getRangeAt(0) : null;
      if (range) {
        // Create the new anchor element
        var el = document.createElement("a");
        el.style.backgroundColor = "pink";
        el.href = this.anchorHref;
        el.innerHTML = this.savedSelText;
        if (this.checked) {
          el.target = "_blank";
        }
        // Delete the originally selected text
        range.deleteContents();
        // Insert the anchor tag
        range.insertNode(el);
        // Ensure that the caret appears at the end
        sel.removeAllRanges();
        range = range.cloneRange();
        range.selectNode(el);
        range.collapse(false);
        sel.addRange(range);
        this.showLinkPopup = false; 
      }
    },
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-06
      • 1970-01-01
      • 2021-08-28
      相关资源
      最近更新 更多