부모 컨테이너를 기준으로 범위의 시작 및 끝 오프셋 가져 오기
이 HTML 요소가 있다고 가정합니다.
<div id="parent">
Hello everyone! <a>This is my home page</a>
<p>Bye!</p>
</div>
그리고 사용자는 마우스로 "홈"을 선택합니다.
나는 #parent
그의 선택 시작에 얼마나 많은 문자가 있는지 (그리고 #parent
그의 선택 끝 에서 얼마나 많은 문자가 끝나는 지) 결정할 수 있기를 원합니다 . HTML 태그를 선택한 경우에도 작동합니다. (그리고 모든 브라우저에서 작동하려면 필요합니다)
range.startOffset
유망 해 보이지만 범위의 직접 컨테이너에만 상대적인 오프셋이며 컨테이너가 텍스트 노드 인 경우에만 문자 오프셋입니다.
최신 정보
주석에서 지적했듯이 내 원래 답변 (아래)은 선택의 끝 또는 캐럿 위치 만 반환합니다. 시작 및 끝 오프셋을 반환하도록 코드를 조정하는 것은 매우 쉽습니다. 다음은 그렇게하는 예입니다.
function getSelectionCharacterOffsetWithin(element) {
var start = 0;
var end = 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.startContainer, range.startOffset);
start = preCaretRange.toString().length;
preCaretRange.setEnd(range.endContainer, range.endOffset);
end = 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("EndToStart", textRange);
start = preCaretTextRange.text.length;
preCaretTextRange.setEndPoint("EndToEnd", textRange);
end = preCaretTextRange.text.length;
}
return { start: start, end: end };
}
function reportSelection() {
var selOffsets = getSelectionCharacterOffsetWithin( document.getElementById("editor") );
document.getElementById("selectionLog").innerHTML = "Selection offsets: " + selOffsets.start + ", " + selOffsets.end;
}
window.onload = function() {
document.addEventListener("selectionchange", reportSelection, false);
document.addEventListener("mouseup", reportSelection, false);
document.addEventListener("mousedown", reportSelection, false);
document.addEventListener("keyup", reportSelection, false);
};
#editor {
padding: 5px;
border: solid green 1px;
}
Select something in the content below:
<div id="editor" contenteditable="true">A <i>wombat</i> is a marsupial native to <b>Australia</b></div>
<div id="selectionLog"></div>
다음은 지정된 요소 내에서 캐럿의 문자 오프셋을 가져 오는 함수입니다. 그러나 이것은 거의 확실하게 줄 바꿈과 불일치가 있고 CSS를 통해 숨겨진 텍스트를 처리하려고 시도하지 않는 순진한 구현입니다 (IE는 이러한 텍스트를 올바르게 무시하지만 다른 브라우저에서는 그렇지 않을 것입니다). 이 모든 것을 제대로 처리하는 것은 까다로울 것입니다. 이제 Rangy 라이브러리에 대해 시도했습니다 .
라이브 예 : http://jsfiddle.net/TjXEG/900/
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;
}
나는 이것이 1 년 된 것을 알고 있지만,이 게시물은 캐럿 위치를 찾는 것에 대한 많은 질문에 대한 상위 검색 결과이며 이것이 유용하다는 것을 알았습니다.
콘텐츠 편집 가능한 div에서 요소를 한 위치에서 다른 위치로 끌어 놓은 후 위의 Tim의 훌륭한 스크립트를 사용하여 새 커서 위치를 찾으려고했습니다. FF 및 IE에서 완벽하게 작동했지만 Chrome에서는 드래그 동작이 드래그 시작과 끝 사이의 모든 콘텐츠를 강조 표시하여 반환 된 결과 caretOffset
가 너무 크거나 작습니다 (선택한 영역의 길이에 따라).
첫 번째 if 문에 몇 줄을 추가하여 텍스트가 선택되었는지 확인하고 그에 따라 결과를 조정했습니다. 새로운 진술은 아래와 같습니다. OP가하려는 것이 아니기 때문에 여기에 추가하는 것이 부적절하다면 저를 용서하십시오.하지만 제가 말했듯이 Caret 위치와 관련된 정보에 대한 여러 검색이 저를이 게시물로 이끌었으므로 다른 사람을 도울 것입니다. .
줄이 추가 된 Tim의 첫 번째 if 문 (*) :
if (typeof window.getSelection != "undefined") {
var range = window.getSelection().getRangeAt(0);
var selected = range.toString().length; // *
var preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.endContainer, range.endOffset);
if(selected){ // *
caretOffset = preCaretRange.toString().length - selected; // *
} else { // *
caretOffset = preCaretRange.toString().length;
} // *
}
며칠 동안 실험 한 후 유망 해 보이는 접근 방식을 찾았습니다. 태그를 올바르게 selectNodeContents()
처리하지 않기 때문에 <br>
.NET node
내부 의 각 텍스트 길이를 결정하는 사용자 지정 알고리즘을 작성 했습니다 contenteditable
. 예를 들어 선택 시작을 계산하기 위해 모든 이전 노드의 텍스트 길이를 합산합니다. 이렇게하면 (다중) 줄 바꿈을 처리 할 수 있습니다.
var editor = null;
var output = null;
const getTextSelection = function (editor) {
const selection = window.getSelection();
if (selection != null && selection.rangeCount > 0) {
const range = selection.getRangeAt(0);
return {
start: getTextLength(editor, range.startContainer, range.startOffset),
end: getTextLength(editor, range.endContainer, range.endOffset)
};
} else
return null;
}
const getTextLength = function (parent, node, offset) {
var textLength = 0;
if (node.nodeName == '#text')
textLength += offset;
else for (var i = 0; i < offset; i++)
textLength += getNodeTextLength(node.childNodes[i]);
if (node != parent)
textLength += getTextLength(parent, node.parentNode, getNodeOffset(node));
return textLength;
}
const getNodeTextLength = function (node) {
var textLength = 0;
if (node.nodeName == 'BR')
textLength = 1;
else if (node.nodeName == '#text')
textLength = node.nodeValue.length;
else if (node.childNodes != null)
for (var i = 0; i < node.childNodes.length; i++)
textLength += getNodeTextLength(node.childNodes[i]);
return textLength;
}
const getNodeOffset = function (node) {
return node == null ? -1 : 1 + getNodeOffset(node.previousSibling);
}
window.onload = function () {
editor = document.querySelector('.editor');
output = document.querySelector('#output');
document.addEventListener('selectionchange', handleSelectionChange);
}
const handleSelectionChange = function () {
if (isEditor(document.activeElement)) {
const textSelection = getTextSelection(document.activeElement);
if (textSelection != null) {
const text = document.activeElement.innerText;
const selection = text.slice(textSelection.start, textSelection.end);
print(`Selection: [${selection}] (Start: ${textSelection.start}, End: ${textSelection.end})`);
} else
print('Selection is null!');
} else
print('Select some text above');
}
const isEditor = function (element) {
return element != null && element.classList.contains('editor');
}
const print = function (message) {
if (output != null)
output.innerText = message;
else
console.log('output is null!');
}
* {
font-family: 'Georgia', sans-serif;
padding: 0;
margin: 0;
}
body {
margin: 16px;
}
.p {
font-size: 16px;
line-height: 24px;
padding: 0 2px;
}
.editor {
border: 1px solid #0000001e;
border-radius: 2px;
white-space: pre-wrap;
}
#output {
margin-top: 16px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="./script.js" async></script>
<link href="./stylesheet.css" rel="stylesheet">
<title>Caret Position</title>
</head>
<body>
<p class="editor" contenteditable="true"><em>Write<br></em><br>some <br>awesome <b><em>text </em></b>here...</p>
<p id="output">Select some text above</p>
</body>
</html>
'Program Tip' 카테고리의 다른 글
부트 스트랩 : 패널 바닥 글에서 왼쪽 및 오른쪽으로 당겨 바닥 글 나누기 (0) | 2020.11.22 |
---|---|
mongoimport를 사용하여 파일에서 mongodb로 json 가져 오기 (0) | 2020.11.22 |
Python 셸에서 인수를 사용하여 파일 실행 (0) | 2020.11.22 |
Grails 2.0에서 Grails 구성에 액세스하는 방법은 무엇입니까? (0) | 2020.11.22 |
선택한 Jquery 플러그인-선택한 값 가져 오기 (0) | 2020.11.22 |