JavaScript實現郵箱字尾提示功能
阿新 • • 發佈:2018-12-12
先來個基礎的
需求
根據下面需求實現如示意圖所示的郵箱輸入提示功能,注意,根據要求只需實現下面功能
- 當用戶沒有任何輸入時,提示框消失
- 當用戶輸入字元後,顯示提示框,並且把使用者輸入的內容自動拼上郵箱字尾進行顯示
- 暫時不用考慮示意圖中的紅色和藍色背景色的邏輯
- 注意使用者輸入中前後空格需要去除
小優化編碼
需求
如果我們輸入的是 [email protected],這個時候出現的提示框內容是
- [email protected]@163.com
- [email protected]@gmail.com
- [email protected]
……
很明顯,上面的提示框不是一個符合使用者需求的提示,我們需要做一些優化:
- 當用戶輸入含有 @ 符號時,我們選取使用者輸入的@前面的字元來和字尾拼接
需求
這下出現的提示好多了,不過使用者如果已經輸入了@1,說明他大概率要輸入163或者126,我們需要讓我們的提示更加符合使用者的期望。滿足以下需求:
- 當用戶輸入了 @ 及部分字尾時,只從 postfixList 選取符合使用者輸入預期的字尾,我們以字首匹配為要求。
- 當用戶輸入不滿足任何字首匹配時,則顯示全部提示
測試用例
- 輸入[email protected]
- 輸入[email protected]>出現提示框,提示[email protected]
- 輸入[email protected]>出現提示框,提示[email protected]
- 輸入[email protected]>出現提示框,提示[email protected]
- 輸入[email protected]>出現提示框,提示[email protected]
- 輸入[email protected]
- 輸入[email protected] (兩個空格)->出現提示框,提示[email protected]
- 輸入[email protected]>出現提示框,出現全部提示
程式碼1
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8" /> 6 <title>郵箱字尾提示1-完成基本提示</title> 7 8 </head> 9 10 <body> 11 <div class="wrapper"> 12 <input type="text" id="input-email"> 13 <ul class="email-sug" id="email-sug-wrapper"> 14 15 </ul> 16 </div> 17 <script> 18 var postfixList = ["163.com", "gmail.com", "126.com", "qq.com", "263.net"]; 19 var txt = document.getElementById("input-email"); 20 var sug = document.getElementById("email-sug-wrapper"); 21 22 // keys.addEventListener("keyup",function(){ 23 // console.log("event handle1"); 24 // }) 25 // keys.addEventListener("keypress",function(){ 26 // console.log("event handle2"); 27 // }) 28 // keys.addEventListener("keydown",function(){ 29 // console.log("event handle3"); 30 // }) 31 // keys.addEventListener("input",function(){ 32 // console.log("event handle4"); 33 // }) 34 35 //經過檢視各個效果,oninput效果最符合需求。 36 txt.oninput = function () { 37 console.log("event handle4"); 38 judge(); 39 add(); 40 41 } 42 function getText() { 43 var inputText = txt.value.trim(); 44 return inputText; 45 } 46 //判斷是否生成新的陣列 47 function postlist() { 48 var userinput = getText(); 49 var newpostlist = new Array(); 50 if (userinput.search('@') != 0) { 51 var len = userinput.search('@'); 52 //用來拼接的使用者輸入內容 = 只使用@之後的字串 53 var x = userinput.substring(len + 1, userinput.length); //取@之後的部分 54 for (var i = 0; i < postfixList.length; i++) { 55 if (postfixList[i].search(x) == 0) { 56 newpostlist.push(postfixList[i]); 57 } 58 } 59 //若@後面沒有字元或者新陣列newpostlist為空,就返回原來的postfixlist 60 if (x === '' || newpostlist == '') { 61 return postfixList; 62 } 63 return newpostlist; 64 } else { 65 return postfixList; 66 } 67 } 68 //根據輸入內容和匹配來生成提示陣列 69 function promptContent() { 70 var x = getText(); 71 var tips = new Array(); 72 if (x.indexOf("@") != -1) { 73 var p = x.slice(0, x.indexOf("@")); 74 for (i = 0; i < postlist().length; i++) { 75 tips[i] = p + "@" + postlist()[i]; 76 } 77 } else { 78 for (i = 0; i < postfixList.length; i++) { 79 tips[i] = x + "@" + postfixList[i]; 80 } 81 } 82 return tips; 83 } 84 //新增提示陣列進入li 85 function add() { 86 var sug = document.getElementById("email-sug-wrapper"); 87 var tips = promptContent(); 88 while (sug.hasChildNodes()) { 89 sug.removeChild(sug.firstChild); 90 } 91 //將之前的列表清除掉,然後重新生成新的列表 92 for (i = 0; i < tips.length; i++) { 93 var tip_li = document.createElement("li"); 94 tip_li.innerHTML = tips[i]; 95 sug.appendChild(tip_li); 96 } 97 } 98 99 function judge() { 100 //判空,是“”沒有內容,不能為“ ” 101 if (getText() == "") { 102 hide(); 103 } else { 104 display(); 105 } 106 107 } 108 109 function hide() { 110 sug.style.display = "none"; 111 } 112 113 function display() { 114 sug.style.display = "block"; 115 } 116 </script> 117 </body> 118 119 </html>
新的需求編碼
需求
上面我們只完成了提示,但提示還沒有直接作用到選擇中,我們現在完成以下需求:
- 使用CSS實現:滑鼠滑過提示框的某一個提示時,這個提示內容背景色變化,表示滑鼠經過了這個DOM節點
- 滑鼠如果點選某個提示,則提示內容進入輸入框,同時提示框消失
- 在上個步驟結束後,在輸入框中任意再輸入字元或刪除字元,則重新開始出現提示框
需求
嘗試在輸入框中輸入<b>,看看提示框發生了什麼
閱讀
設計
我們需要在兩個地方進行處理,一個是在生成提示內容那裡,對於特殊字元進行轉義編碼,另一個是在把滑鼠點選的提示框內容轉回輸入框時進行解碼。
程式碼2
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>郵箱字尾提示2-新增樣式和監聽滑鼠點選和轉碼內容</title> <style> #input-email{ width: 300px; height: 30px; } .email-sug{ width: 300px; list-style: none; padding: 0px; margin: 0px; border: 2px solid rgba(134, 132, 132,0.3); border-top:none; display: none; /* 初始不顯示,避免邊框出現 */ } .email-sug li{ width: 300px; height: 30px; background-color: #ffffff; color: darkgrey; line-height: 30px; } .email-sug li:hover{ background-color:pink; } </style> </head> <body> <div class="wrapper"> <input type="text" id="input-email"> <ul class="email-sug" id="email-sug-wrapper"> </ul> </div> <script> var postfixList = ["163.com", "gmail.com", "126.com", "qq.com", "263.net"]; var txt = document.getElementById("input-email"); var sug = document.getElementById("email-sug-wrapper"); sug.addEventListener("click",function(ev){ //採用事件代理,監聽父級點選事件,通過target獲取當前li var ev=ev||window.event; var target=ev.target||ev.srcElement; if(target.nodeName.toLowerCase()=="li"){ hide(); return txt.value=htmlDecode( target.innerHTML); //解碼 //return txt.value= target.innerHTML; } }) txt.oninput = function () { console.log("event handle4"); judge(); add(); } function getText() { var inputText = txt.value.trim(); return inputText; } //判斷是否生成新的陣列 function postlist() { var userinput = getText(); var newpostlist = new Array(); if (userinput.search('@') != 0) { var len = userinput.search('@'); //用來拼接的使用者輸入內容 = 只使用@之後的字串 var x = userinput.substring(len + 1, userinput.length); //取@之後的部分 for (var i = 0; i < postfixList.length; i++) { if (postfixList[i].search(x) == 0) { newpostlist.push(postfixList[i]); } } //若@後面沒有字元或者新陣列newpostlist為空,就返回原來的postfixlist if (x === '' || newpostlist == '') { return postfixList; } return newpostlist; } else { return postfixList; } } //根據輸入內容和匹配來生成提示陣列 function promptContent() { var x = htmlEncode(getText()) //轉碼; // var x=getText(); var tips = new Array(); if (x.indexOf("@") != -1) { var p = x.slice(0, x.indexOf("@")); for (i = 0; i < postlist().length; i++) { tips[i] = p + "@" + postlist()[i]; } } else { for (i = 0; i < postfixList.length; i++) { tips[i] = x + "@" + postfixList[i]; } } return tips; } //新增提示陣列進入li function add() { var sug = document.getElementById("email-sug-wrapper"); var tips = promptContent(); while (sug.hasChildNodes()) { sug.removeChild(sug.firstChild); } //將之前的列表清除掉,然後重新生成新的列表 for (i = 0; i < tips.length; i++) { var tip_li = document.createElement("li"); tip_li.innerHTML = tips[i]; sug.appendChild(tip_li); } } function judge() { //判空,是“”沒有內容,不能為“ ” if (getText() == "") { hide(); } else { display(); } } function hide() { sug.style.display = "none"; } function display() { sug.style.display = "block"; } /*1.用瀏覽器內部轉換器實現html轉碼*/ function htmlEncode(html){ //1.首先動態建立一個容器標籤元素,如DIV var temp = document.createElement ("div"); //2.然後將要轉換的字串設定為這個元素的innerText(ie支援)或者textContent(火狐,google支援) (temp.textContent != undefined ) ? (temp.textContent = html) : (temp.innerText = html); //3.最後返回這個元素的innerHTML,即得到經過HTML編碼轉換的字串了 var output = temp.innerHTML; temp = null; return output; } /*2.用瀏覽器內部轉換器實現html解碼*/ function htmlDecode(text){ //1.首先動態建立一個容器標籤元素,如DIV var temp = document.createElement("div"); //2.然後將要轉換的字串設定為這個元素的innerHTML(ie,火狐,google都支援) temp.innerHTML = text; //3.最後返回這個元素的innerText(ie支援)或者textContent(火狐,google支援),即得到經過HTML解碼的字串了。 var output = temp.innerText || temp.textContent; temp = null; return output; } </script> </body> </html>
加上鍵盤
需求
我們給提示框加上3個按鍵的功能,分別是回車和上下鍵,使得可以通過鍵盤操作進行提示框的選擇
- 當有提示框的時候,預設第一個提示為被選擇狀態,用一個和滑鼠滑過不一樣的背景色來標識
- 當有輸入框的時候,按上鍵,可以向上移動選擇狀態,如果按鍵之前的被選擇提示是第一個,則被選狀態移到最下面一個
- 當有輸入框的時候,按下鍵,可以向下移動選擇狀態,如果按鍵之前的被選擇提示是最後一個,則被選狀態移到第一個
- 當有輸入框時,按回車鍵,則將當前被選中狀態的提示內容,放到輸入框中,並隱藏提示框
- 當沒有輸入框的時候,這3個鍵盤按鍵無響應
- 當用戶輸入發生改變的時候,選擇狀態都重新切回到第一個提示
優化體驗
需求
當我們進入頁面,或者當我們點選滑鼠進行提示選擇後,輸入框的焦點就不在了,所以請你優化一下使用者體驗:
- 一進入頁面就將焦點放在輸入框中
- 使用者點選滑鼠,進行提示選擇後,焦點依然在輸入框中
- 使用者按ESC鍵的時候,對使用者輸入進行全選
程式碼3
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8" /> 6 <title>郵箱字尾提示3-新增鍵盤響應及輸入框焦點優化</title> 7 <style> 8 #input-email{ 9 width: 300px; 10 height: 30px; 11 } 12 .email-sug{ 13 width: 300px; 14 list-style: none; 15 padding: 0px; 16 margin: 0px; 17 border: 2px solid rgba(134, 132, 132,0.3); 18 border-top:none; 19 display: none; 20 /* 初始不顯示,避免邊框出現 */ 21 } 22 .email-sug li{ 23 width: 300px; 24 height: 30px; 25 background-color: #ffffff; 26 color: darkgrey; 27 line-height: 30px; 28 overflow: hidden; 29 padding-left: 10px; 30 box-sizing: border-box; 31 } 32 .email-sug li:hover{ 33 background-color:skyblue; 34 } 35 .email-sug li.active{ 36 background-color:pink; 37 } 38 </style> 39 </head> 40 41 <body> 42 <div class="wrapper"> 43 <input type="text" id="input-email" autofocus="autofocus"> 44 <ul class="email-sug" id="email-sug-wrapper"> 45 46 </ul> 47 </div> 48 <script> 49 var postfixList = ["163.com", "gmail.com", "126.com", "qq.com", "263.net"]; 50 var txt = document.getElementById("input-email"); 51 var sug = document.getElementById("email-sug-wrapper"); 52 var nowSelectTipIndex = 0; 53 54 //獲取輸入文字 55 txt.oninput = function (e) { 56 console.log("event handle4"); 57 //按下的是內容,則重置選中狀態,座標清零,避免游標位置已經計算存入。 58 if (!(e.keyCode == 40 || e.keyCode == 38 || e.keyCode == 13)) { 59 nowSelectTipIndex = 0; 60 } 61 judge(); 62 add(); 63 } 64 //點選事件響應 65 sug.addEventListener("click", function (ev) { 66 //採用事件代理,監聽父級點選事件,通過target獲取當前li 67 var ev = ev || window.event; 68 var target = ev.target || ev.srcElement; 69 if (target.nodeName.toLowerCase() == "li") { 70 hide(); 71 txt.focus(); //寫在return之前,不然無效 72 return txt.value = htmlDecode(target.innerHTML); //解碼 73 //return txt.value= target.innerHTML; 74 } 75 }) 76 //鍵盤事件響應 77 document.addEventListener("keydown", function (e) { 78 var e = e || window.event; 79 var key = e.which || e.keyCode; 80 var list = document.getElementsByTagName("li"); 81 //向下鍵 82 if (key == 40) { 83 for (i = 0; i < list.length; i++) { 84 list[i].setAttribute("class", ""); 85 } 86 nowSelectTipIndex++; 87 if (nowSelectTipIndex + 1 > list.length) { 88 nowSelectTipIndex = 0; 89 } 90 list[nowSelectTipIndex].setAttribute("class", "active"); 91 } 92 //向上鍵 93 if (key == 38) { 94 for (i = 0; i < list.length; i++) { 95 list[i].setAttribute("class", ""); 96 } 97 nowSelectTipIndex--; 98 if (nowSelectTipIndex < 0) { 99 nowSelectTipIndex = list.length - 1; 100 } 101 list[nowSelectTipIndex].setAttribute("class", "active"); 102 } 103 //回車鍵 104 if (key == 13) { 105 var x = document.getElementsByClassName("active"); 106 txt.value = htmlDecode(x[0].innerHTML); //用textcontent會去除html標籤例如<b>。。 107 hide(); 108 } 109 if (key == 27) { 110 txt.setSelectionRange(0, -1); //ESC全選上文字框內容 111 hide(); 112 } 113 114 }) 115 //獲取輸入內容,並去除首尾空格 116 function getText() { 117 var inputText = txt.value.trim(); 118 return inputText; 119 } 120 //判斷是否生成新的陣列 121 function postlist() { 122 var userinput = getText(); 123 var newpostlist = new Array(); 124 if (userinput.search('@') != 0) { 125 var len = userinput.search('@'); 126 //用來拼接的使用者輸入內容 = 只使用@之後的字串 127 var x = userinput.substring(len + 1, userinput.length); //取@之後的部分 128 for (var i = 0; i < postfixList.length; i++) { 129 if (postfixList[i].search(x) == 0) { 130 newpostlist.push(postfixList[i]); 131 } 132 } 133 //若@後面沒有字元或者新陣列newpostlist為空,就返回原來的postfixlist 134 if (x === '' || newpostlist == '') { 135 return postfixList; 136 } 137 return newpostlist; 138 } else { 139 return postfixList; 140 } 141 } 142 //根據輸入內容和匹配來生成提示陣列 143 function promptContent() { 144 var x = htmlEncode(getText()); //轉碼; 145 // var x=getText(); 146 var tips = new Array(); 147 if (x.indexOf("@") != -1) { 148 var p = x.slice(0, x.indexOf("@")); 149 for (i = 0; i < postlist().length; i++) { 150 tips[i] = p + "@" + postlist()[i]; 151 } 152 } else { 153 for (i = 0; i < postfixList.length; i++) { 154 tips[i] = x + "@" + postfixList[i]; 155 } 156 } 157 return tips; 158 } 159 //新增提示陣列進入li 160 function add() { 161 var sug = document.getElementById("email-sug-wrapper"); 162 var tips = promptContent(); 163 while (sug.hasChildNodes()) { 164 sug.removeChild(sug.firstChild); 165 } 166 //將之前的列表清除掉,然後重新生成新的列表 167 for (i = 0; i < tips.length; i++) { 168 var tip_li = document.createElement("li"); 169 tip_li.innerHTML = tips[i]; 170 sug.appendChild(tip_li); 171 } 172 //初始選擇第一項為選中狀態,加類名變粉色(需要生成li之後再呼叫)。 173 var list = document.getElementsByTagName("li"); 174 list[0].setAttribute("class", "active"); 175 } 176 177 function judge() { 178 //判空,是“”沒有內容,不能為“ ” 179 if (getText() == "") { 180 hide(); 181 } else { 182 display(); 183 } 184 185 } 186 //控制提示列表隱藏 187 function hide() { 188 sug.style.display = "none"; 189 } 190 //控制提示列表顯示 191 function display() { 192 sug.style.display = "block"; 193 } 194 195 /*1.用瀏覽器內部轉換器實現html轉碼*/ 196 function htmlEncode(html) { 197 //1.首先動態建立一個容器標籤元素,如DIV 198 var temp = document.createElement("div"); 199 //2.然後將要轉換的字串設定為這個元素的innerText(ie支援)或者textContent(火狐,google支援) 200 (temp.textContent != undefined) ? (temp.textContent = html) : (temp.innerText = html); 201 //3.最後返回這個元素的innerHTML,即得到經過HTML編碼轉換的字串了 202 var output = temp.innerHTML; 203 temp = null; 204 return output; 205 } 206 /*2.用瀏覽器內部轉換器實現html解碼*/ 207 function htmlDecode(text) { 208 //1.首先動態建立一個容器標籤元素,如DIV 209 var temp = document.createElement("div"); 210 //2.然後將要轉換的字串設定為這個元素的innerHTML(ie,火狐,google都支援) 211 temp.innerHTML = text; 212 //3.最後返回這個元素的innerText(ie支援)或者textContent(火狐,google支援),即得到經過HTML解碼的字串了。 213 var output = temp.innerText || temp.textContent; 214 temp = null; 215 return output; 216 } 217 </script> 218 </body> 219 220 </html>
最終效果如圖: