最近在項目中碰到一個比較棘手的問題: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對象的getBookmark和moveToBookmark兩個方法,前者獲取一個對象,這個對象記錄了當前編輯器中光標的位置信息,後者根據這個位置信息還原光標的位置。代碼以下:
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,利用第二種方式就能夠實現。
現在瀏覽器五法八門,各自對標準的支持也不同,致使了前端開發者作了大量的工做來彌補兼容性,無論怎樣,相信會愈來愈好~~~