使用contenteditable div获取并设置光标位置

时间:2015-12-04 15:26:59

标签: javascript jquery html

我有一个令人满意的div,我希望能够让用户插入链接,图片或YouTube视频等内容。目前这就是我所拥有的:

function addLink() {
  var link = $('#url').val();
  $('#editor').focus();
  document.execCommand('createLink', false, link);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Text Editor -->
<div id="editor" contenteditable="true"></div>

<!-- Add Link -->
<input type="text" id="url">
<button onclick="addLink()">Submit</button>

如您所见,用户必须输入单独的文本框才能输入链接地址。因此,当链接添加到编辑器时,它不会添加到指针/插入符所在的位置。

我的问题是如何获取和设置指针/插入符的位置。我已经看到了其他问题,例如this for setting the pointer,但我更倾向于使用所有现代浏览器都支持的解决方案,包括Chrome,Safari,Firefox和IE9 +。

有什么想法吗?感谢。

修改

我发现下面的代码获得了位置,但它只根据它所在的行获取位置。例如,如果我有这个(其中|是光标):

This is some text
And som|e more text

然后我将返回值7,而不是24。

function getPosition() {
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt) {
            return sel.getRangeAt(0).startOffset;
        }
    }
    return null;
}

4 个答案:

答案 0 :(得分:9)

现场有大量相关信息。这个适用于我和我的客户。

DEMO

https://stackoverflow.com/a/6249440/2813224

function setCaret(line, col) {
  var ele = document.getElementById("editable");
  var rng = document.createRange();
  var sel = window.getSelection();
  rng.setStart(ele.childNodes[line], col);
  rng.collapse(true);
  sel.removeAllRanges();
  sel.addRange(range);
  ele.focus();
}

//https://stackoverflow.com/a/6249440/2813224

var line = document.getElementById('ln').value;
var col = document.getElementById('cl').value;
var btn = document.getElementById('btn');
btn.addEventListener('click', function(event) {
  var lineSet = parseInt(line, 10);
  var colSet = parseInt(col, 10);
  setCaret(lineSet, colSet);
}, true);
<div id="editable" contenteditable="true">
  <br/>text text text text text text
  <br/>text text text text text text
  <br/>text text text text text text
  <br/>
  <br/>
</div>
<fieldset>
  <button id="btn">focus</button>
  <input type="button" class="fontStyle" onclick="document.execCommand('italic',false,null);" value="I" title="Italicize Highlighted Text">
  <input type="button" class="fontStyle" onclick="document.execCommand('bold',false,null);" value="B" title="Bold Highlighted Text">
  <input id="ln" placeholder="Line#" />
  <input id="cl" placeholder="Column#" />
</fieldset>

答案 1 :(得分:2)

我试图找到解决方案,

只需一点帮助就可以完善它。 这是我在SO和我的exp。

上找到的答案的组合

它很棘手,它很乱......但如果你必须,你可以使用它,但它需要一些工作来支持内部链接(如果光标在锚点上它将在锚点内创建锚点)

这是JS:

var lastPos;
var curNode = 0;
function setCaret() {
  curNode=0;
  var el = document.getElementById("editor");
  var range = document.createRange();
  var sel = window.getSelection();

  console.log(el.childNodes);
  if (el.childNodes.length > 0) {
      while (lastPos > el.childNodes[curNode].childNodes[0].textContent.length) {
      lastPos = lastPos - el.childNodes[curNode].childNodes[0].textContent.length;
      curNode++;

      }
      range.setStart(el.childNodes[curNode].childNodes[0], lastPos);
      range.collapse(true);
      sel.removeAllRanges();
      sel.addRange(range);
  }
  el.focus();
};


function savePos() {
  lastPos = getCaretCharacterOffsetWithin(document.getElementById('editor'));
}

function addLink() {
  console.log(lastPos);

  setCaret();
  console.log(getCaretCharacterOffsetWithin(document.getElementById('editor')));

  console.log('focus');

  // $("#editor").focus();
  var link = $('#url').val();
  document.execCommand('createLink', false, link);

}

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;
}

fiddle

答案 2 :(得分:2)

一个好的富文本编辑器是目前最难做的事情之一,它本身就是一个项目(不友好的API,大量的极端情况,跨浏览器差异,列表继续)。我强烈建议您尝试找到现有的解决方案。

可以使用的一些库包括:

答案 3 :(得分:0)

这就是你要求的,在你的赏金中:在下面的例子中,你可以看到如何检测点击鼠标的实际点的确切字符数:

   <!-- Text Editor -->
   <div id="editor" class="divClass" contenteditable="true">type here some text</div>


    <script>



   document.getElementById("editor").addEventListener("mouseup", function(key) {

alert(getCaretCharacterOffsetWithin(document.getElementById("editor")));

}, 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;
}
 </script>