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
Get and set cursor position with contenteditable div
提问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:
可以使用的一些库包括:
- Quill (http://quilljs.com)
- WYSGIHTML (http://wysihtml.com)
- CodeMirror library (http://codemirror.net)
- 羽毛笔 ( http://quilljs.com)
- WYSGIHTML ( http://wysihtml.com)
- CodeMirror 库 ( http://codemirror.net)
回答by zer00ne
There's a ton of related info onsite. This one works for me and my clients.
现场有大量相关信息。这个对我和我的客户都有效。
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;
}
回答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>