javascript 使用 contenteditable div 获取和设置光标位置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34091730/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 17:13:58  来源:igfitidea点击:

Get and set cursor position with contenteditable div

javascriptjqueryhtml

提问by Pav Sidhu

I have a contenteditable div which I would like to be able to have users insert things such as links, images or YouTube videos. At the moment this is what I have:

我有一个 contenteditable 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>

As you can see, the user has to type into a separate text box to enter the link address. As a result, when the link is added to the editor, it is not added to the position that the pointer/caret was on.

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

My question is how I can get and set the location of the pointer/caret. I have seen other questions such as this for setting the pointerhowever I would prefer to have a solution which is supported in all modern browsers, including Chrome, Safari, Firefox and IE9+.

我的问题是如何获取和设置指针/插入符号的位置。我已经看到了其他问题,例如设置指针的问题,但是我更喜欢所有现代浏览器都支持的解决方案,包括 Chrome、Safari、Firefox 和 IE9+。

Any ideas? Thanks.

有任何想法吗?谢谢。

Edit:

编辑:

I found the code below which gets the position however, it only gets the position according to the line it is on. For example if I had this (where |is the cursor):

我发现下面的代码可以获取位置,但是它只能根据它所在的行获取位置。例如,如果我有这个(|光标在哪里):

This is some text
And som|e more text

Then I would be returned the value 7, not 24.

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

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

采纳答案by SpeedySan

A good rich-text editor is one of the harder things to do currently, and is pretty much a project by itself (unfriendly API, huge number of corner cases, cross-browser differences, the list goes on). I would strongly advise you to try and find an existing solution.

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

Some libraries that can be used include:

可以使用的一些库包括:

回答by zer00ne

There's a ton of related info onsite. This one works for me and my clients.

现场有大量相关信息。这个对我和我的客户都有效。

DEMO

演示

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

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>

回答by Ziv Weissman

I have tried to find a solution,

我试图找到解决办法,

With a little help it can be perfected. It is a combination of answers I've found on SO, and my exp.

有一点帮助,它可以完善。这是我在 SO 上找到的答案和我的经验的组合。

Its tricky, its messy... but if you must, you can use it but it requires a bit of work to support inner links (if you cursor is on an anchor it will create anchor inside anchor)

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

Here's the JS:

这是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

小提琴

回答by Gaucho

This is what you asked for, in your bounty: on the following example you can see how to detect the exact number of characters of the actual point where you clicked the mouse on:

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

   <!-- 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>