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


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

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

解決嘗試

一、利用模態彈出框

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

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

二、保存光標位置,選擇后還原(1)

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

 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中,直接可以用編輯對象獲取當前的編輯位置,下面是光標還原的代碼:

 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 }

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

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

二、保存光標位置,選擇后還原(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,利用第二種方式就可以實現。

 

如今瀏覽器五法八門,各自對標准的支持也不一樣,導致了前端開發者做了大量的工作來彌補兼容性,不管怎樣,相信會越來越好~~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM