強制回應視窗唯讀狀態下要進行複製很麻煩,無法選定文本也無法進行複製、編輯、右鍵瀏覽器菜單。本文提供一種解決這個問題的方法:使用JavaScript指令碼,選定控制項文本,再使用CTRL+C進行複製。
一、一些後面要用到的方法:
/* 功能: 判斷是否字串類型 參數: 無調用方法: 對象.isString()NOTE: (typeof(oSource) == 'string')不能正確識別new String()產生的字串對象*/String.prototype.isString = String.prototype.isString || ( function() { return ('[object String]' == Object.prototype.toString.call(this)); });/*功能: 擷取控制項文本。*/function GetControlText(oSource) { return (oSource.innerText || oSource.value || ""); //oSource.selectorText || }/*功能: 設定控制項可複製NOTE: 選定後就可以使用Ctrl+C按鍵組合進行複製! 但不能使用瀏覽器右鍵菜單*/function SetCanCopy(oSource) { oSource.contentEditable = true; oSource.disabled = false;//可能不需要修改?}
判斷是否字串的方法抄自百度開源js庫;擷取控制項文本可能還有其他情況沒考慮到;設定控制項contentEditable = true;不是一定需要,不過設定了可以使得選定控制項文本的操作更加準確(在文本選定方法fnSelectText中體現),具體來說,就是雙擊控制項(控制項外部不算),選定的文本就是點擊的控制項的文本,而如果不設定contentEditable為true,則很大機率會選定同頁面出現相同文本的第一個地方。
二、儲存控制項原始屬性
/* 現場儲存與恢複 *//* 臨時變數, 用於儲存需要複製文本的控制項的原始狀態 */var OriginStatus = OriginStatus || { };/*功能: 儲存控制項原始狀態*/function SaveOriginStatus(oSource) { //oSource.disabled = 'disabled';//禁用後不能複製 //oSource.readOnly = true;//無效, 還是可以複製 OriginStatus.contentEditable = oSource.contentEditable; OriginStatus.disabled = oSource.disabled;}/*功能: 還原控制項原始狀態*/function RecoverOriginStatus(oSource) { oSource.contentEditable = OriginStatus.contentEditable; oSource.disabled = OriginStatus.disabled;}
三、滑鼠左鍵按住不放進行控制項文本選擇
/* 滑鼠左鍵按住不放進行控制項文本選擇 */var isBound = false;document.attachEvent("onmousedown", function() { isBound = true;});document.attachEvent("onmouseup", function() { isBound = false;});
方法內註冊事件用attachEvent,沒有考慮到非IE的情況。
四、選中要複製的控制項的文本
/*功能: 選中要複製的控制項的文本。NOTE: 方法內部是選中控制項所有文本, 而非部分.*/function fnSelectText(oSource, e) { if (!oSource) return; e = e || window.event; e.returnValue = false; //textarea採用自身選定功能. 注意textarea不能被disabled if(oSource.type == "textarea") return; //設定為可編輯, 是為了減少findText方法選中第一個的幾率 SaveOriginStatus(oSource); SetCanCopy(oSource); var sSourceText = GetControlText(oSource); var caretPos = sSourceText.length; //文本長度 if (caretPos == 0) return; if (oSource.createTextRange) { var r = oSource.createTextRange(); r.move('character', caretPos); r.select(); } else if (oSource.setSelectionRang) { oSource.setSelectionRange(caretPos, caretPos); oSource.focus(); } else { //TODO: BUG, 如果頁面有多個相同文本, 則會選中第一個 var r = document.selection.createRange();//或者document.body.createTextRange(); r.findText(sSourceText); //動態添加的內容, 可能會導致異常: htmlfile: Could not complete the operation due to error 800a025e. r.select(); } RecoverOriginStatus(oSource);}
注意:方法內部是選中控制項所有文本, 而非部分。另外還有個BUG未解決:如果頁面有多個相同文本, 則會選中第一個。
五、頁面事件註冊
//雙擊控制項選定文本事件document.attachEvent("ondblclick", function(e) { //強制回應視窗下Label控制項不屬於document.activeElement if(window.event.srcElement) { fnSelectText(window.event.srcElement, window.event || e); }});//滑鼠左鍵按住移動選中事件document.attachEvent("onmouseover", function(e) { if(!!isBound) { if(window.event.srcElement) { fnSelectText(window.event.srcElement, window.event || e); } }});//滑鼠右鍵事件//document.attachEvent("onmousedown", function(e) {// e = e || window.event;// //點擊滑鼠右鍵// if(e.button == 2) {// var oSource = window.event.srcElement;// if(oSource.type == "textarea") return;// else {// //請同步選取Ctrl和C按鍵組合進行複製或者長按滑鼠左鍵將文本拖拉到富文字編輯器中!// alert("請同步選取Ctrl和C按鍵組合進行複製!");// //window.event.cancelBubble = true; // //e.returnValue = false;// }// //createCopyTextarea(oSource);// //window.event.srcElement.contentEditable = true;// }//});document.attachEvent("oncontextmenu", function(e) { var oSource = window.event.srcElement; if(oSource.type == "textarea") return; else { alert("請同步選取Ctrl和C按鍵組合進行複製!"); }});
將事件註冊到document,而不是某個控制項,主要是考慮到頁面如果有多個控制項的話,逐個控制項註冊比較麻煩。這樣處理也符合使用者習慣,滑鼠左鍵選定或者雙擊選定文本,然後按Ctrl+C按鍵組合複製即可。
六、使用方法
假設指令檔名為CopyDataOnModalWindow.js,檔案存放路徑為"http://www.cnblogs.com/Scripts/js/CopyDataOnModalWindow.js",那麼可以如下調用:
<script type="text/javascript">if(window.document.readyState == "interactive") { if (!window.opener) { //如果是在強制回應視窗下, 才引用指令碼 var s = document.createElement('script'); s.src = "http://www.cnblogs.com/Scripts/js/CopyDataOnModalWindow.js"; s.type = "text/javascript"; window.document.getElementsByTagName("head")[0].appendChild(s); } else { }}</script>
注意:我不確定 !window.opener就一定是強制回應視窗,如果您有判斷強制回應視窗更好的方法,請留言告知。
這段指令碼放在頁面最後即可。
〇、結束語及遺留問題
指令碼如此處理,可以不用汙染頁面,只需要複製指令碼調用方法即可。遺憾的是,沒有解決JavaScript操作剪貼簿出現異常的問題;也沒處理好一些細節。
說明:
1.textarea控制項如果不是disabled狀態的話,即使是readOnly,是可以選定並且瀏覽器右鍵菜單可以彈出,所以處理時排除掉textarea;如果是disabled狀態的話,雙擊、滑鼠點擊事件均不會被觸發,暫時沒有想到有什麼其他辦法可以解決。
2.select控制項的文本也無法選定。但select控制項disabled狀態下事件可以被觸發。
3.選定後,無法右鍵彈出瀏覽器原生菜單;如果是自訂菜單,暫時無法解決JavaScript操作剪貼簿出現異常的問題;
4.細節問題
bug: 選擇控制項文本, 如果頁面有多處相同文本, 將會選中第一個(當然也可以複製到文本)
bug: 選定控制項文本, 滑鼠左鍵在選定地區按下後不放, 將文本拖拉到其他地方再釋放, 這個時候isBound 還是 true;或者某種情形下,點擊右鍵,移動滑鼠會使得滑鼠移動過的控制項逐個選定文本。這個無關大雅,不過沒有深入處理。
----end----