今天朋友問我一個js的問題,他是這么描述的:
頁面上有些許文本框,但是要求獲得焦點后就必須為其輸入數據. 如果光標離開,
驗證是否已經填入數據,如果沒有填入數據就彈出提示對話框. 結束對話框后,
要求該文本框獲得焦點,可以繼續輸入.
起初我沒有在意,但是看了他的要求,我覺得應該很簡單吧!后來看了看,似乎並不容易.
問題出現在怎么添加事件執行代碼. 先貼一段代碼,
為id為text的div標簽下的所有文本框添加失去焦點的事件
1 <html> 2 <head> 3 <title></title> 4 <script type="text/javascript"> 5 function initialize() { 6 var text = document.getElementById("text").getElementsByTagName("input"); 7 for(var i = 0; i < text.length; i++) { 8 text[i].onblur = function() { 9 // 失去焦點的事件 10 } 11 } 12 } 13 14 onload = function() { 15 initialize(); 16 } 17 </script> 18 </head> 19 <body> 20 <div id="text"> 21 <input type="text" /><br /> 22 <input type="text" /><br /> 23 <input type="text" /><br /> 24 <input type="text" /><br /> 25 </div> 26 </body> 27 </html>
關於這個題目的問題就在於如何使文本框獲得焦點.
要求失去焦點的時候檢查是否有數據,沒有數據彈出對話框,並要求當前文本框獲得焦點
簡單的想法就是
1 text[i].onblur = function() { 2 // 長度為零表示沒有數據 3 if(this.value.length == 0) { 4 alert("請輸入數據"); // 彈出對話框 5 this.focus(); // 獲得焦點 6 } 7 }
感覺沒什么問題,但是一到瀏覽器中執行就悲劇了.
因為會死在一個窗體事件的調用上. 怎么回事兒呢?
原來第一個文本框獲得焦點的時候,如果沒有輸入數據,直接跳到第二個文本框
(或者是點擊頁面的其他地方,也或者讓光標離開瀏覽器),都會觸發離開的事件
1、如果是點擊文本框,將鼠標離開文本框點擊,也不點擊其他文本框
-> 離開時首先判斷文本框中是否有數據,即value.length == 0
-> 如果沒有數據,則彈出對話框"請輸入數據",同時文本框失去焦點
-> 待用戶點擊確認后,該文本框獲得焦點
這樣沒有什么問題,但是如果點擊的是下一個文本框就不一樣了
2、點擊第一個文本框,然后點擊另一個文本框(悲劇了)
-> 第一個文本框失去焦點,第二個文本框得到焦點就觸發了事件
-> 添加代碼,得到焦點的代碼,看看當第二個文本框獲得焦點時事件的觸發順序
-> 先為每個文本框添加一個title屬性,並一次賦值: 1,2,3,4
1 <div id="text"> 2 <input type="text" title="1" /><br /> 3 <input type="text" title="2" /><br /> 4 <input type="text" title="3" /><br /> 5 <input type="text" title="4" /><br /> 6 </div>
-> 再添加js代碼
function initialize() { var text = document.getElementById("text").getElementsByTagName("input"); for(var i = 0; i < text.length; i++) { text[i].onfocus = function() { alert(this.title + "獲得焦點"); } text[i].onblur = function() { alert(this.title + "請輸入數據"); this.focus(); } } }
-> 使用IE8瀏覽器測試,鼠標離開首先彈出對話框"1請輸入數據"
-> 隨后是"2獲得焦點", "2請輸入數據", "1獲得焦點", "1請輸入數據", "2獲得焦點", "2請輸入數據", ...如此反復
-> 分析一下執行過程
-> 鼠標點擊第二個文本框,觸發失去焦點方法,彈出對話框"1請輸入數據"
-> 點擊彈出對話框確定按鈕后,瀏覽器激活,第二個文本框獲得焦點,觸發方法,顯示"2獲得焦點",但是第一步中方法this.focus()沒有執行
-> 結束這個彈出對話框,this.focus()方法被執行,由於this指第一個文本框,因此第一個文本框獲得焦點
-> 焦點離開第二個文本框,觸發離開的事件,顯示"2請輸入數據"
-> 結束后第一個文本框獲得焦點,顯示"1獲得焦點",但是剛剛離開第二個方法的this.focus()方法沒有執行
-> 因此結束彈出對話框后,執行this.focus()方法,第二個文本框獲得焦點,繼續離開第一個對話框,觸發事件
-> 可以了解到,這里就進入了死循環,不斷在兩個文本框中跳來跳去
要解決這個問題,基本上就是在離開的時候獲得焦點的情況
-> 期望的執行,應該是:第一個文本框獲得焦點,點擊第二個文本框,由於第一個文本框中沒有數據,彈出對話框
-> 對話框結束,第二個文本框獲得焦點,執行第一個對話框中的this.focus()方法,此時跳回第一個文本框
-> 關鍵點來了,在這里從第二個文本框中失去焦點,第一個文本框獲得焦點時,不應該觸發離開第二個文本框的事件
由於文本框添加方法是一起添加的,因此這里需要考慮,應該離開文本框時不是總是彈出對話框,也就是說,除了value.length == 0外還需要一個條件 理一理思路,要求應該是
-> 文本框離開的時候應該判斷一下,應該操作的文本框是哪一個
-> 例如,開始點擊第一個文本框時,應該操作的是第一個文本框
-> 當點擊第二個文本框時,判斷一下,當前操作文本框是不是第一個文本框
-> 顯然是,因此彈出對話框"1請輸入數據",然后第二個文本框獲得焦點
-> 第一個方法的this.focus()方法執行,第二個文本框失去焦點,第一個文本框獲得焦點
-> 此時離開第二個文本框的時候,判斷當前文本框. 顯然當前文本框是第一個,因此不用彈出對話框
有了這個思路,就知道了,只要添加一個全局變量記錄當前對花框即可
但是什么時候為這個變量賦值呢?當然是第一次獲得焦點的時候. 不過這是有點疑慮.
-> 在第一個文本框選中的時候,點擊第二個文本框時,不應該為這個變量賦值
-> 但是一開始第一個文本框獲得焦點時,需要為這個變量賦值
-> 如果第一個文本框正常輸入數據后,切刀第二個文本框,應該為這個變量賦值
因此基本操作為
-> 定義一個變量current,賦值為null
-> 由於所有方法都需要判斷,將變量定義成全局的
1 var current = null;
-> 當文本框獲得焦點的時候,判斷current是否為null,為空時為其賦值,否則不變
if(!current) {
current = this;
}
-> 那么這個變量可以記錄第一次選中的文本框,在失去焦點的方法中,如果當前文本框與這個變量不匹配,就不彈出"請輸入數據"的對話框
1 if(this == current && this.value.length == 0) { // 判斷是否是當前文本框,以及是否有數據 2 alert(this.title + "請輸入數據"); 3 this.focus(); 4 }
-> 然后在正確輸入數據離開該文本框時,將current清空,賦值為null
1 if(this == current && this.value.length == 0) { 2 alert(this.title + "請輸入數據"); 3 this.focus(); 4 } 5 else { 6 current = null; 7 }
那么js代碼可以修改為
1 <script type="text/javascript"> 2 var current = null; 3 function initialize() { 4 var text = document.getElementById("text").getElementsByTagName("input"); 5 for(var i = 0; i < text.length; i++) { 6 text[i].onfocus = function() { 7 if(!current) { 8 current = this; 9 } 10 } 11 text[i].onblur = function() { 12 if(this == current && this.value.length == 0) { 13 alert(this.title + "請輸入數據"); 14 this.focus(); 15 } 16 else { 17 current = null; 18 } 19 } 20 } 21 } 22 onload = function() { 23 initialize(); 24 } 25 </script>