既然是基於Selection對象的,我們就要先獲取這個Selection對象,它就在document對象中,直接使用document.selection就可以找到它。它提供了createRange方法,可以創建壹個TextRange對象。(創建TextRange對象的方法不止壹種,其它方法本文就不介紹了)得到TextRange對象以後就可以操作選區了。看下面代碼
<!DOCTYPE html>
<style>
div {width:600px;border:1px solid red;}
</style>
<div contenteditable="true" id="editor">
金樽清酒鬥十千,玉盤珍饈值萬錢。<br/>
停杯投箸不能食,拔劍四顧心茫然。<br/>
欲渡黃河冰塞川,將登太行雪滿山。<br/>
閑來垂釣碧溪上,忽復乘舟夢日邊。<br/>
行路難!行路難!多歧路,今安在?<br/>
長風破浪會有時,直掛雲帆濟滄海。<br/>
</div>
<script>
//變量初始化
var range,editor;
range=document.selection.createRange();
editor=document.getElementById("editor");
//選中editor內的所有文字
range.moveToElementText(editor);
//拋棄選區的結束位置
range.collapse();
//把當前選區的結束位置向後移動16個字符
range.moveEnd("character",16);
//在界面上選中這個選區
range.select();
</script> 看完這段代碼,妳就應該明白如果選中壹個文本選區了。這裏值得壹提的是,collapse這個方法是把結束位置拋棄掉,並不是簡單的設置到開始位置。結束位置被拋棄掉以後,只要沒有給它重新設置位置,它就壹直都會等於開始位置。即使妳修改了開始位置,結束位置還是會在修改後的開始位置上。接著看代碼把,為了方便,接下來的代碼我只寫JS部分,HTML部分和第壹個例子中的壹樣。//變量初始化
var range,editor;
range=document.selection.createRange();
editor=document.getElementById("editor");
//選中editor內的所有文字
range.moveToElementText(editor);
//拋棄選區的結束位置
range.collapse();
//把當前選區的開始位置向後移動17個字符
range.moveStart("character",17);
//把當前選區的結束位置向後移動16個字符
range.moveEnd("character",16);
//在界面上選中這個選區
range.select(); 這個代碼會選中第二行,妳會發現moveEnd的第二個參數是16而不是17+16。這就是上面說的拋棄結束位置後在重新定義它之前會和開始位置相同。設置位置大概就是這麽多內容了,接著是獲取壹個文本選區的位置,其實這個操作沒有必要,如果妳想保存壹個文本選區的位置,直接保存TextRange對象就好了,沒必要精確到第幾個字符。不過為了某些奇葩的需求,我在這裏還是介紹壹下獲取選區位置信息的方法。獲取這個信息可沒有選中位置那麽容易,需要用到壹個叫做setEndPoint的方法。由於TextRange對象無法直接獲取數值,只能使用setEndPoint這個方法來把壹個TextRange對象的開始或結束位置賦值到另壹個TextRange對象上,這樣我們就可以通過計算字數的方式來精確位置了。至於這個setEndPoint的具體用法,妳可以參考本文最後的鏈接去看看官方提供的說明。下面是獲取選區位置的代碼。
//獲取編輯器對象
var editor=document.getElementById("editor");
//鼠標事件
document.onmouseup=function(){
//變量聲明
var st,cr,l,r;
//創建壹個文本選區,並把光標設置到editor的開始位置
st=document.selection.createRange();
st.moveToElementText(editor);
st.collapse();
//創建選區對象(默認會選中當前區域)
cr=document.selection.createRange();
//把st的end設置成cr的start
st.setEndPoint("EndToStart",cr);
//開始位置就是st的文本長度了
l=st.text.length
//結束位置就是開始位置加上區間的文本長度
r=l+cr.text.length
//輸出位置信息
alert("開始位置:"+l+"\n"+"結束位置:"+r);
}; 知道了以上這些,在低版本瀏覽器中操作文本選區應該就基本沒啥問題了。接著來說說新版瀏覽器的Range對象。
首先是Selection這個對象,它不像舊標準那樣是壹個document的屬性了,妳必須用getSelection這個方法去獲取,這個方法是在window對象上的,所以我們可以直接使用它。而新標準的Range對象和舊標準的區別很大,不是從Selection對象創建的,而是從document對象創建的,妳可以使用document.createRange來創建壹個新選區。新標準的Selection對象和舊標準的也有很大差別,與其說是差別,不如說是完全兩個不同的概念。新標準的Selection對象是可以同時包含多個Range對象的,用getRangeAt方法去獲取具體哪個對象,參數是Range對象組的下標。接著我們來實現壹下選中第二行文字的功能。看代碼
//變量初始化
var editor,selection,range,s;
editor=document.getElementById("editor");
s=editor.childNodes;
selection=getSelection();
range=document.createRange();
//設置range的開始和結束點
range.setStart(s[2],0);
range.setEnd(s[3],0);
//移除selection中原有的所有range
selection.removeAllRanges();
//把這個新的range添加到selection中
selection.addRange(range); 如果妳用舊標準的眼光去看新標準的代碼妳壹定會壹頭霧水。標準的Range對象,可以說是非常非常精確,精確的讓妳抓狂。它精確到文本節點的第幾個字符,而且還包括空白字符。所以Range對象計算起來非常費勁,但是它的邏輯很完整,完全沒有破壞HTML原本的格式,不像舊標準的TextRange對象,為了方便計算把HTML標簽都拋棄了。上面的這段代碼最難懂的也許就是設置開始和結束位置的地方了吧。setStart和setEnd方法都有兩個參數,第壹個參數是節點,第二個參數有兩種意義。如果第壹個參數是文本節點,那麽第二個參數就是文字的位置。如果不是文本節點,那麽第二個參數就是它子節點的位置。用語言描述有點拗口,不夠仔細想想應該可以明白。上面代碼中的s[2]就是editor的第三個子節點(第壹個下標為0),如果妳用Chrome的調試工具去看,妳會發現,第三個子節點就是第二行的文本節點,後面的參數是0,表示這個文本節點中的第壹個字符。後面的s[3]也是類似的,只不過它是指向BR標簽,BR裏面沒有文字和子節點,那麽setEnd(s[3],0)就是把結束位置設置到BR本身的位置。其它的代碼從註釋上就可以理解了,我就不多說了。接著來看看如何獲取光標位置在哪個節點的第幾個字符。新版的獲取代碼會比舊版的簡單很多,由於有對象,我就不用alert輸出了改用conslode.log,妳們調試的時候可以按出控制臺查看信息。下面是代碼
//獲取selection對象
var selection=getSelection();
//鼠標事件
document.onmouseup=function(){
console.log("開始對象",selection.anchorNode);
console.log("開始位置",selection.anchorOffset);
console.log("結束對象",selection.focusNode);
console.log("結束位置",selection.focusOffset);
}; 所有的數據妳都可以從selection這個對象中找到,不需要訪問range。比起舊標準的操作方法,這個是壹個很大的優勢。上面這個代碼也沒什麽好說的,開始點的數據保存在anchorNode和anchorOffset中,結束點的位置則保存在focusNode和focusOffset中,只要記住就好了。
學會上面這麽多之後,無論在什麽瀏覽器上對選取的操作都可以很順利的進行了。如果還有什麽疑問可以到本站的提問頻道問問神奇的海螺。下面是官方提供的幾個文檔,有興趣的話可以看看。