這兩天出了這么一個需求,輸入稅號的時候,需要自動將其轉化為半角大寫,并且阻止標點符號中文漢字的輸入。(下面會有:全半角轉換、文本框選中、光標位置判斷、設置光標位置 這些內容)
然后我就開始了慢慢查找資料之路。
首先查了全半角的區別以及如何轉化。
var str = "中文;;a";for (var i = 0; i < str.length; i++) { if (str[i].match(/[/u0000-/u00ff]/)) { console.log("半角字符"); } else if (str[i].match(/[/uff00-/uffff]/)) { console.log("全角字符 " + str[i] + " " + toSBC(str[i])); } else { console.log(str[i]); // 除了數字英文之外的文本,包括中文等各國文字。 }}
這是兩者的區別,將文字轉成unicode之后,進行比較即可,兩者均有自己的范圍,半角為0x20~0x7E,全角為0xFF01~0xFF5E。(這是16進制,前面的0x是代表是16進制)
轉化的話除了空格不同之外,其他均為全角-半角=65248(0xFEE0)
具體的轉化函數如下:(這是網上的一種比較靠譜的方法,但是網上的方法普遍把SBC和DBC寫反了,我這里糾正了一下。)
// 轉全角字符function toSBC(str) { var result = ""; var len = str.length; for (var i = 0; i < len; i++) { var cCode = str.charCodeAt(i); //全角與半角相差(除空格外):65248(十進制) cCode = (cCode>=0x0021 && cCode<=0x007E)?(cCode + 65248) : cCode; //處理空格 cCode = (cCode==0x0020)?0x03000:cCode; result += String.fromCharCode(cCode); } return result;}// 轉半角字符function toDBC(str) { var result = ""; var len = str.length; for (var i = 0; i < len; i++) { var cCode = str.charCodeAt(i); //全角與半角相差(除空格外):65248(十進制) cCode = (cCode>=0xFF01 && cCode<=0xFF5E)?(cCode - 65248) : cCode; //處理空格 cCode = (cCode==0x03000)?0x0020:cCode; result += String.fromCharCode(cCode); } return result;}
全角半角的區別也找完了,開始想辦法轉化,用的是input方法。
var oldValue = "";var $thisDom; // 假裝有jquery的dom元素$thisDom.unbind().bind("input", function (e) { var reg = /^[0-9A-Za-z]*$/; var str = toDBC(e.target.value).toUpperCase(); if (reg.test(str)) { oldValue = str; $(this).val(str); } else { $(this).val(oldValue); }});
但是有一個問題,那就是光標有問題,始終在最后一位輸入的時候沒問題,但是在中間輸入,光標始終會跳到最后一位。于是又有了下面的光標相關知識。
在網上找到了下列相關代碼,用來控制光標位置。
function getCursortPosition(ctrl){ var CaretPos = 0; if (document.selection) { ctrl.focus(); var Sel = document.selection.createRange(); Sel.moveStart('character', -ctrl.value.length); CaretPos = Sel.text.length; } else if (ctrl.selectionStart || ctrl.selectionStart == '0') { CaretPos = ctrl.selectionStart; } return (CaretPos);}function setCaretPosition(ctrl, pos){ if (ctrl.setSelectionRange) { ctrl.focus(); ctrl.setSelectionRange(pos, pos); } else if (ctrl.createTextRange) { var range = ctrl.createTextRange(); range.collapse(true); range.moveEnd('character', pos); range.moveStart('character', pos); range.select(); }}
這兩個分別是獲取光標位置以及設置光標位置。這里用到的是textRange對象。
TextRange對象是動態HTML(DHTML)的高級特性,使用它可以實現很多和文本有關的任務,例如搜索和選擇文本。文本范圍讓您可以選擇性的將字符、單詞和句子從文檔中挑選出來。TextRange對象是在HTML文檔將要顯示的文本流上建立開始和結束位置的抽象對象。
下面是TextRange的常用屬性與方法:
屬性:
boundingHeight 獲取綁定TextRange對象的矩形的高度
boundingLeft 獲取綁定TextRange 對象的矩形左邊緣和包含TextRange對象的左側之間的距離
offsetLeft 獲取對象相對于版面或由offsetParent屬性指定的父坐標的計算左側位置
offsetTop 獲取對象相對于版面或由offsetParent屬性指定的父坐標的計算頂端位置
htmlText 獲取綁定TextRange對象的矩形的寬度
text 設置或獲取范圍內包含的文本
方法:
moveStart 更改范圍的開始位置
moveEnd 更改范圍的結束位置
collapse 將插入點移動到當前范圍的開始或結尾
move 折疊給定文本范圍并將空范圍移動給定單元數
execCommand 在當前文檔、當前選中區或給定范圍上執行命令
select 將當前選擇區置為當前對象
findText 在文本中搜索文本并將范圍的開始和結束點設置為包圍搜索字符串。
具體使用可見其他人的文章,地址是://www.survivalescaperooms.com/article/105787.htm
回到正題,于是我把上述代碼拼進了我的代碼中。
function toDBC(str) { var result = ""; var len = str.length; for (var i = 0; i < len; i++) { var cCode = str.charCodeAt(i); //全角與半角相差(除空格外):65248(十進制) cCode = (cCode>=0xFF01 && cCode<=0xFF5E)?(cCode - 65248) : cCode; //處理空格 cCode = (cCode==0x03000)?0x0020:cCode; result += String.fromCharCode(cCode); } return result;}function getCursortPosition(ctrl){ var CaretPos = 0; if (document.selection) { ctrl.focus(); var Sel = document.selection.createRange(); Sel.moveStart('character', -ctrl.value.length); CaretPos = Sel.text.length; } else if (ctrl.selectionStart || ctrl.selectionStart == '0') { CaretPos = ctrl.selectionStart; } return (CaretPos);}function setCaretPosition(ctrl, pos){ if (ctrl.setSelectionRange) { ctrl.focus(); ctrl.setSelectionRange(pos, pos); } else if (ctrl.createTextRange) { var range = ctrl.createTextRange(); range.collapse(true); range.moveEnd('character', pos); range.moveStart('character', pos); range.select(); }}var oldValue = this.model.get("taxNo");$taxNoDom.unbind().bind("input", function (e) { var reg = /^[0-9A-Za-z]*$/; var position = getCursortPosition($taxNoDom[0]); var str = toDBC(e.target.value).toUpperCase(); if (reg.test(str) && str.length <= 25) { oldValue = str; $(this).val(str); setCaretPosition($taxNoDom[0], position); } else { $(this).val(oldValue); setCaretPosition($taxNoDom[0], position - 1); }});
上述代碼中我自己寫的就是最下面的綁定事件,仔細看一下應該都是可以看懂的。但是上述代碼有一個bug,其實也算是getCursortPosition這個方法的bug。
那就是在中文輸入法的時候,輸入的字母在input事件執行的時候是選中格式,光標在該字母之前,以至于位置跟想象的有偏差,在正確的時候打出來的字一直在光標之后。
當時我很苦惱感覺人生無望啊。。想了幾種方法:
1. 默認觸發鍵盤左箭頭再觸發右箭頭。這樣不管是不是選中光標都應該是正確的位置了。
2. 查看當前頁面中是否有選中的文字。如果有選中的文字,就把返回的光標位置+1。
網上查了一下第一種方法,立馬就放棄了。相關資料也很少,而且局限性相當大,瀏覽器之間差異也大,怎么看都不像是會是一種好方法。
然后找到了第二種方法的方法。window.getSelection和document.selection
IE9以下支持:document.selection
IE9、Firefox、Safari、Chrome和Opera支持:window.getSelection()
(由于我們公司項目只支持ie9及以上,就沒有嘗試document.selection)
我自己試了一下,如果有選中的文字的時候window.getSelection().type === "Range",如果沒有選中window.getSelection().type === "Caret"。
于是最終的代碼如下:
function toDBC(str) { var result = ""; var len = str.length; for (var i = 0; i < len; i++) { var cCode = str.charCodeAt(i); //全角與半角相差(除空格外):65248(十進制) cCode = (cCode>=0xFF01 && cCode<=0xFF5E)?(cCode - 65248) : cCode; //處理空格 cCode = (cCode==0x03000)?0x0020:cCode; result += String.fromCharCode(cCode); } return result;}function getCursortPosition(ctrl){ var CaretPos = 0; if (document.selection) { ctrl.focus(); var Sel = document.selection.createRange(); Sel.moveStart('character', -ctrl.value.length); CaretPos = Sel.text.length; } else if (ctrl.selectionStart || ctrl.selectionStart == '0') { if (window.getSelection().type === "Range") { CaretPos = ctrl.selectionStart + 1; } else { CaretPos = ctrl.selectionStart; } } return (CaretPos);}function setCaretPosition(ctrl, pos){ if (ctrl.setSelectionRange) { ctrl.focus(); ctrl.setSelectionRange(pos, pos); } else if (ctrl.createTextRange) { var range = ctrl.createTextRange(); range.collapse(true); range.moveEnd('character', pos); range.moveStart('character', pos); range.select(); }}var oldValue = this.model.get("commercialTax").taxNo;$taxNoDom.unbind().bind("input", function (e) { var reg = /^[0-9A-Za-z]*$/; var position = getCursortPosition($taxNoDom[0]); var str = toDBC(e.target.value).toUpperCase(); if (reg.test(str) && str.length <= 25) { oldValue = str; $(this).val(str); setCaretPosition($taxNoDom[0], position); } else { $(this).val(oldValue); setCaretPosition($taxNoDom[0], position - 1); }});
以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持武林網!
新聞熱點
疑難解答