JavaScript Iframe富文本編輯器中的光標定位

最近在項目中碰到一個比較棘手的問題:html

  在iframe富文本編輯器中,有個工具欄,這個工具欄在iframe標籤以外,工具欄上有一個按鈕,點擊該按鈕向iframe正在編輯中的光標處插入一個圖片,圖片會插入到當前光標所在的位置。但因爲需求的須要,點擊該按鈕後須要彈出一個詳細選項浮動層,選擇詳細的類型後再插入,如此,問題來了,當我點擊了該按鈕,浮動層顯示出來後,iframe已經失去焦點,並不知道以前正在編輯的位置,因此編輯器默認把圖片插入到編輯器內容的最前邊(內部處理),編輯器及浮動層需求以下圖:前端

解決嘗試
瀏覽器

1、利用模態彈出框編輯器

  首先聲明這種方式是可行的,由於模態對話框會保持iframe編輯器的編輯狀態,模態對話框的返回值可直接插入到以前正在編輯的光標位置,就像上面圖中其餘按鈕同樣,它們經過點擊事件直接插入。可是對於上述需求,只是在該按鈕位置添加了一個子類型選擇列表框,用模態窗口顯然得不到更好的人性化體驗,這也不是咱們所想要的。函數

  這時候若是能保存以前光標的編輯位置就行了,的確,在按鈕的點擊事件中,彈出浮動層的同時也保存好光標的位置,而後選擇了詳細類型後再將光標還原到原來的位置插入圖片信息,通過嘗試和摸索,使人欣喜的是,這種方式是可行的。工具

2、保存光標位置,選擇後還原(1)測試

  這種方法主要經過document的selection對象來實現,在按鈕的點擊事件處理程序中,獲取當前光標據文檔開頭的位置(即長度),而後保存,在選擇了子類型後,根據以前保存的位置還原光標,而後插入圖片信息,代碼片斷以下:spa

 1 //記錄光標的位置,以備後續還原使用
 2 var LastPos = 0;
 3 //保存當前光標的位置
 4 function SaveCusorPos() {
 5     //獲取編輯器焦點
 6     var wobj = document.getElementById("myiframe").contentWindow;
 7     wobj.focus();
 8     if (document.selection) {
 9         //ie,利用範圍進行計算
10         var sText = wobj.document.selection.createRange();
11         //清除掉當前選中的內容
12         if (sText.htmlText != undefined && sText.htmlText != "") {
13             wobj.document.selection.clear();
14         }
15         //選擇當前光標位置到文檔開頭之間的內容(以字符爲單位)
16         sText.moveStart('character', -wobj.document.body.innerHTML.toString().length);
17         //計算選擇內容的長度
18         LastPos = sText.text.length + FliterHtmlTag(sText.htmlText) + 1; //; //sText.htmlText.length; //
19     }
20     else if (wobj.selectionStart || wobj.selectionStart == "0") {
21         //firefox,直接讀取編輯位置
22         LastPos = wobj.selectionStart;
23     }
24 }

上述代碼不難理解,在ie中須要用範圍計算當前光標位置距離文檔開頭的距離,而在firefox中,直接能夠用編輯對象獲取當前的編輯位置,下面是光標還原的代碼:firefox

 1 //把光標還原到以前保存的位置
 2 function SetCusorPos() {
 3     //獲取編輯器對象焦點
 4     var wobj = document.getElementById("myiframe").contentWindow;
 5     wobj.focus();
 6     if (wobj.document.body.setSelectionRange) {
 7         //firefox,直接經過函數定位光標
 8         wobj.document.body.setSelectionRange(LastPos, LastPos);
 9     }
10     else if (wobj.document.selection.createRange()) {
11         //ie,用selection對象進行選擇
12         var range = wobj.document.selection.createRange();
13         range.collapse(true);
14         //將選擇區域的開始位置和結束位置都移動到以前保存的點
15         range.moveEnd('character', LastPos);
16         range.moveStart('character', LastPos);
17         //定位光標的位置
18         range.select();
19     }
20 }

在不一樣的瀏覽器中,處理方式均不同,不過有一點是相通的,它們都是經過將選取的開始位置和結束位置重合來定位光標。code

  經測試,這種方式是可行的,但它只能在純文本處理的時候有用(IE中),問題在於這個保存點的計算,經過選區Text的length獲取的長度是隻是這個選區的文字長度,它並不能過濾多媒體元素(如圖片、音視頻等),這些元素在這個length中並無包括,故存在多媒體元素的時候,這個光標保存點是不許的,會在實際位置的前面插入。此外,選區還有另一個屬性htmlText,獲取它的長度又如何呢!?答案也是不行,這個長度包含了選區中html標籤的全部字符,好比換行,段落等都被計算在內,這個光標保存點比實際的要大的多,會在實際位置的後面插入。

2、保存光標位置,選擇後還原(2)

  上述兩種方法都有本身的缺陷,通過摸索和查閱相關資料,在IE中有第三種方法能夠實現此功能,就是selection對象的getBookmarkmoveToBookmark兩個方法,前者獲取一個對象,這個對象記錄了當前編輯器中光標的位置信息,後者根據這個位置信息還原光標的位置。代碼以下:

 1 //存儲以前光標位置信息的對象
 2 var ieSelectionBookMark = null;
 3 //保存當前光標的位置
 4 function SaveCusorPos() {
 5     //編輯器獲取焦點
 6     var wobj = document.getElementById("myiframe").contentWindow;
 7     wobj.focus();
 8     if (document.selection) {
 9         //獲取當前光標的位置
10         var rangeObj = wobj.document.selection.createRange();
11         ieSelectionBookMark = rangeObj.getBookmark();
12     }
13 }
14 //把光標還原到以前保存的位置
15 function SetCusorPos() {
16     //編輯器獲取焦點
17     var wobj = document.getElementById("myiframe").contentWindow;
18     wobj.focus();
19     if (ieSelectionBookMark) {
20         //還原光標的位置
21         var rangeObj = wobj.document.selection.createRange();
22         rangeObj.moveToBookmark(ieSelectionBookMark);
23         rangeObj.select();
24         ieSelectionBookMark = null;
25     }
26 }

上述代碼改寫了第二種方法中的兩個函數,比較簡潔,但這種方式在IE8中測試經過,其餘不一樣版本瀏覽器中有待進一步驗證,其餘瀏覽器如firefox,利用第二種方式就能夠實現。

 

現在瀏覽器五法八門,各自對標準的支持也不同,致使了前端開發者作了大量的工做來彌補兼容性,無論怎樣,相信會愈來愈好~~~

相關文章
相關標籤/搜索