js獲取光標(biāo)位置的最新方法
1.概念和原理
DOM中并沒有直接獲取光標(biāo)位置的方法,那么我們只能間接來獲取光標(biāo)位置。DOM支持獲取光標(biāo)選中的范圍,我們可以以此為切入點,來獲取或定位光標(biāo)的位置。當(dāng)選取范圍起始點和結(jié)束點一樣時,就是光標(biāo)插入的位置。
1.1 術(shù)語
- anchor(瞄點):選區(qū)起點。
- focus(焦點):選區(qū)終點。
- range(范圍):選區(qū)范圍,包含整個節(jié)點或節(jié)點的一部分。
1.2 Selection
Selection: Selection對象表示用戶選擇的文本范圍或插入符號的位置。
經(jīng)過實驗發(fā)現(xiàn)Selection選取的節(jié)點范圍都是塊級節(jié)點。input 和 texteare 并不能作為Selection的節(jié)點
Selection對象存在于window對象上,可以通過window.getSelection()獲取示例。
屬性:
- anchorNode: 選區(qū)起點的節(jié)點。
- anchorOffset:選區(qū)的起點位置。
- focusNode:選區(qū)終點的節(jié)點。
- focusOffset:選區(qū)的終點位置。
- isCollapsed:起點和終點是否重疊。
- rangeCount:選區(qū)包含的range數(shù)目。
方法
- getRangeAt(index):獲取指定的選取范圍。
- addRange(range):將一個范圍添加到Selection對象中。
- removeRange():移出指定的范圍。
- removeAllRanges():移出所有range對象。
- collapse(parentNode,offset):將光標(biāo)移動到parentNode節(jié)點的offset位置。
- collapseToStart():取消當(dāng)前選區(qū),并把光標(biāo)定位在原選區(qū)的最開始處,如果此時光標(biāo)所處的位置是可編輯的,且它獲得了焦點,則光標(biāo)會在原地閃爍。
- collapseToEnd():取消當(dāng)前選區(qū),并將光標(biāo)定位到原選取的最末位。如果此時光標(biāo)所處的位置是可編輯的,且它獲得了焦點,則光標(biāo)會在原地閃爍。
- extend(node,offset):將終點位置移動到node節(jié)點的offset位置。
- modify(alter,direction,granularity):通過alter方式(move/extend)來改變光標(biāo)位置,移動方向為direction(left/right),移動單位為granularity。
- containsNode(aNode,aPartlyContained):判斷aNode是否包含在Selection中。aPartlyContained為false表示全包含,為true表示只要部分包含即可。
- toString():放回當(dāng)前Selection對象的字符串。
1.3 Range
Range對象表示一個Selection的選擇范圍,一個Selection可以包含多個Range。
獲取對象
document.createRange():創(chuàng)建一個Range。
selection.getRangeAt(index):獲取指定的Range。
屬性
- collapsed:判斷起始位置是否重合。
- endContaniner:range終點節(jié)點。
- endOffset:range的終點位置。
- startContaniner:ranstartge起點節(jié)點。
- startOffset:range的起點位置。
- commonAncestorContainer:包含起始點的節(jié)點。
方法
- setStart(startNode,startOffset):設(shè)置范圍在startNode的起始位置為startOffset。
- setEnd(endNode,endOffset):設(shè)置范圍在endNode的起始位置為endOffset。
- selectNode(referenceNode):設(shè)置range的節(jié)點為referenceNode。
- selectNodeContents(referenceNode):設(shè)置range的內(nèi)容為referenceNode。
- collapse(toStart):向邊界點折疊range,即是設(shè)置光標(biāo)位置,toStart默認(rèn)為false,表示光標(biāo)定位在節(jié)點末尾。true表示光標(biāo)定位在節(jié)點起點。
- cloneContents():克隆一個range的內(nèi)容片段。
- deleteContents():刪除range的內(nèi)容片段。
- extractContents():將range的內(nèi)容從文檔樹移動到文檔片段中。
- insertNode(newNode):在range的其實位置插入新的節(jié)點。
- surroundContents(newNode):將range對象的內(nèi)容移動到新的節(jié)點中。
- cloneRange():克隆一個range對象。
- detach():釋放當(dāng)前range。
1.4 input/textarea
在html5中,可輸入性表單元素(input/textarea)都存在以下屬性。不支持IE6/7。
selectionDirection:forward | backward | none,選區(qū)方向
selectionEnd:選區(qū)終點位置
selectionStart:選區(qū)起點位置
setSelectionRange(selectionStart, selectionEnd, [selectionDirection]):設(shè)置獲取焦點的輸入性元素的選區(qū)范圍。
2.獲取光標(biāo)位置
2.1 可編輯div獲取光標(biāo)位置
//獲取當(dāng)前光標(biāo)位置
const getCursortPosition = function (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) {//選中的區(qū)域
var range = win.getSelection().getRangeAt(0);
var preCaretRange = range.cloneRange();//克隆一個選中區(qū)域
preCaretRange.selectNodeContents(element);//設(shè)置選中區(qū)域的節(jié)點內(nèi)容為當(dāng)前節(jié)點
preCaretRange.setEnd(range.endContainer, range.endOffset); //重置選中區(qū)域的結(jié)束位置
caretOffset = preCaretRange.toString().length;
}
} else if ((sel = doc.selection) && sel.type != "Control") {//IE
var textRange = sel.createRange();
var preCaretTextRange = doc.body.createTextRange();
preCaretTextRange.moveToElementText(element);
preCaretTextRange.setEndPoint("EndToEnd", textRange);
caretOffset = preCaretTextRange.text.length;
}
return caretOffset;
}獲取光標(biāo)的位置是先通過獲取鼠標(biāo)的選取范圍,然后克隆該選取范圍,修改克隆范圍的結(jié)束位置,這樣克隆的范圍就只剩下起點到結(jié)束點的內(nèi)容,光標(biāo)之后的內(nèi)容被截取扔掉了。所以可以通過剩余內(nèi)容的長度來確定光標(biāo)位置。之所以要克隆一個選取范圍出來,是為了避免修改光標(biāo)結(jié)束位置時影響到原先內(nèi)容。
2.2 input/textarea獲取光標(biāo)位置
//輸入框獲取光標(biāo)
const getPosition = function (element) {
let cursorPos = 0;
if (document.selection) {//IE
var selectRange = document.selection.createRange();
selectRange.moveStart('character', -element.value.length);
cursorPos = selectRange.text.length;
} else if (element.selectionStart || element.selectionStart == '0') {
cursorPos = element.selectionStart;
}
return cursorPos;
}3.設(shè)置光標(biāo)位置
3.1 可編輯div設(shè)置光標(biāo)位置
//設(shè)置光標(biāo)位置
const setCaretPosition = function (element, pos) {
var range, selection;
if (document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
{
range = document.createRange();//創(chuàng)建一個選中區(qū)域
range.selectNodeContents(element);//選中節(jié)點的內(nèi)容
if(element.innerHTML.length > 0) {
range.setStart(element.childNodes[0], pos); //設(shè)置光標(biāo)起始為指定位置
}
range.collapse(true); //設(shè)置選中區(qū)域為一個點
selection = window.getSelection();//獲取當(dāng)前選中區(qū)域
selection.removeAllRanges();//移出所有的選中范圍
selection.addRange(range);//添加新建的范圍
}
else if (document.selection)//IE 8 and lower
{
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
range.moveToElementText(element);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
range.select();//Select the range (make it the visible selection
}
}3.2 input/textarea獲取光標(biāo)位置
// 設(shè)置光標(biāo)位置
function setCaretPosition(textDom, pos){
if(textDom.setSelectionRange) {
// IE Support
textDom.focus();
textDom.setSelectionRange(pos, pos);
}else if (textDom.createTextRange) {
// Firefox support
var range = textDom.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}4.示例
<html>
<head>
<title>光標(biāo)測試</title>
<style>
p {
display: flex;
flex-direction: row;
}
.btn {
height: 24px;
margin: 0 10px;
}
.edit-div {
display: inline-block;
width: 225px;
border: 1px solid #decdcd;
}
</style>
<script>
function getCursortPosition(e) {
var eleP = e.target.parentNode; //獲取父級元素
var pos = 0;
if (e.target.nodeName == "DIV") {
pos = getDivPosition(e.target);
} else {
pos = getPosition(e.target);
}
var spanEle = (eleP.childNodes)[7];
spanEle.innerText = pos;
}
//可編輯div獲取坐標(biāo)
const getDivPosition = function (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) {//選中的區(qū)域
var range = win.getSelection().getRangeAt(0);
var preCaretRange = range.cloneRange();//克隆一個選中區(qū)域
preCaretRange.selectNodeContents(element);//設(shè)置選中區(qū)域的節(jié)點內(nèi)容為當(dāng)前節(jié)點
preCaretRange.setEnd(range.endContainer, range.endOffset); //重置選中區(qū)域的結(jié)束位置
caretOffset = preCaretRange.toString().length;
}
} else if ((sel = doc.selection) && sel.type != "Control") {//IE
var textRange = sel.createRange();
var preCaretTextRange = doc.body.createTextRange();
preCaretTextRange.moveToElementText(element);
preCaretTextRange.setEndPoint("EndToEnd", textRange);
caretOffset = preCaretTextRange.text.length;
}
return caretOffset;
}
//輸入框獲取光標(biāo)
const getPosition = function (element) {
let cursorPos = 0;
if (document.selection) {//IE
var selectRange = document.selection.createRange();
selectRange.moveStart('character', -element.value.length);
cursorPos = selectRange.text.length;
} else if (element.selectionStart || element.selectionStart == '0') {
cursorPos = element.selectionStart;
}
return cursorPos;
}
</script>
</head>
<body>
<p>
<label>輸入框測試:</label>
<input type="text" style="width:220px" onclick="getCursortPosition(event);" />
<span>光標(biāo)位置:</span>
<span></span>
</p>
<p>
<label>文本框測試:</label>
<textarea rows="5" style="width:220px" onclick="getCursortPosition(event);"></textarea>
<span>光標(biāo)位置:</span>
<span></span>
</p>
<div>
<label>可編輯div:</label>
<div contenteditable="true" class="edit-div" onclick="getCursortPosition(event);"></div>
<span>光標(biāo)位置:</span>
<span></span>
</div>
</body>
</html>總結(jié)
到此這篇關(guān)于js獲取光標(biāo)位置的文章就介紹到這了,更多相關(guān)js獲取光標(biāo)位置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript字符串替換函數(shù)如何一次性全部替換掉
這篇文章主要介紹了JS字符串替換函數(shù)replace如何一次性全部替換的相關(guān)資料,需要的朋友可以參考下2015-10-10
微信小程序教程系列之頁面跳轉(zhuǎn)和參數(shù)傳遞(6)
這篇文章主要為大家詳細介紹了微信小程序教程系列之頁面跳轉(zhuǎn)和參數(shù)傳遞,微信小程序提供了3種頁面跳轉(zhuǎn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
Typescript學(xué)習(xí)之接口interface舉例詳解
TypeScript是JavaScript的一個超集,主要提供了類型系統(tǒng)和對ES6+的支持,TypeScript的核心原則之一是對值所具有的結(jié)構(gòu)進行類型檢查,這篇文章主要給大家介紹了關(guān)于Typescript學(xué)習(xí)之接口interface的相關(guān)資料,需要的朋友可以參考下2024-03-03

