今日開始學習写代码之前开始画流程图
- 今日開始學習写代码之前开始画流程图
目標:
建立一個純js搜索提示框
- 当用户没有任何输入时,提示框消失
- 当用户输入字符后,显示提示框,并且把用户输入的内容自动拼上邮箱后缀进行显示
- 注意用户输入中前后空格需要去除
心得:
整體的思路並不難,需要花時間的地方是如何將需求包裝成個別的函數。
首先整個的事件會跟input有關所以在每次輸入時調用函數
var input = document.querySelector('#email-input')
var ul = document.querySelector('#email-sug-wrapper')
var postfixList = ['163.com', 'gmail.com', '126.com', 'qq.com', '263.net'];
input.addEventListener('input', function (e) {
addPrompt()
display()
selected()
eventAdd()
})
獲取用戶的輸入,並將每次用戶輸入的前後空白刪除(trim),再將結果返回,這裡也可以封裝成一個函數,每次調用時就會獲取其結果
function getInput() {
//拿到input输入框的输入内容trim后返回
var input1 = input.value;
return input1.trim();
}
封裝一個讓提示框顯示或隱藏的函數,因為在之後我們需要反覆調用提示框的顯示和隱藏
先獲取用戶輸入的的內容並去掉前後的空白格的
function show() {
ul.style.display = 'block'
}
function hide() {
ul.style.display = 'none'
}
再來定義提示框什麼時候出現與隱藏 先獲取用戶輸入的內容並且將其內容去掉前後空格的值(trim),再來判斷如果其值為空,則表示用戶沒有輸入,此時提示框隱藏,若相反,則表示用戶在輸入,讓其提示框顯示
function display() {
var out = getInput()
if (out === '') {
hide();
} else {
show();
ul.children[0].classList.add('active')
}
}
最後在遍歷已提供的數組值(儲存著信箱後綴)
在每次遍歷都把後綴的值和用戶輸入的值拼接
在這裡,因為有多個值,所以建立個數組,將數值存入數組
最後將其值顯示在提示框裡。
function setPrompt() {
var input1 = getInput()
var res = []
for (var i = 0; i < postfixList.length; i++) {
res[res.length] = input1 + '@' + postfixList[i]
}
}
return res
}
function addPrompt() {
/* 获取用户输入
遍历postfixList {
把用户输入和每一个postfix进行结合成为每一个Li
}
返回生成的提示内容*/
var result = setPrompt()
var len = ul.childNodes.length;
for (var i = len - 1; i >= 0; i--) {
ul.removeChild(ul.childNodes[i]);
}
for (var i = 0; i < result.length; i++) {
ul.appendChild.innerHTML = ''
var li = document.createElement('li')
li.innerHTML = result[i]
ul.appendChild(li)
}
}
優化1
此時大部分架構已經出來,但仍有很多地方可以優化。
如果我们输入的是 abc@1,这个时候出现的提示框内容是
abc@1@163.com
abc@1@gmail.com
abc@1@126.com
很明显,上面的提示框不是一个符合用户需求的提示,我们需要做一些优化:
- 当用户输入含有 @ 符号时,我们选取用户输入的@前面的字符来和后缀拼接
這個問題很簡單只要用if加入條件,如果數入值裡有@那就擷取@以前的數值
function setPrompt() {
var input1 = getInput()
var input2;
var res = []
if(input.indexOf('@')===-1){
input2 = input1.slice(0, input1.indexOf('@');
}else{
input2=input1;
}
for (var i = 0; i < postfixList.length; i++) {
res[res.length] = input2+ '@' + postfixList[i]
}
}
return res
}
不过用户如果已经输入了@1,说明他大概率要输入163或者126,我们需要让我们的提示更加符合用户的期望。满足以下需求:
- 当用户输入了 @ 及部分后缀时,只从 postfixList 选取符合用户输入预期的后缀,我们以前缀匹配为要求。
- 当用户输入不满足任何前缀匹配时,则显示全部提示
當用戶輸入的值含有@時,將@前的值保存在input2變量裡,將@後的值保存在input3裡,若不含@則將值input2=input1
然後再次循環後綴並判斷是否和input3相同,若有則將input2和相同的後綴拼接起來,並顯示
若否,input2則和所有後綴拼接,並顯示。
這裡用到了閥流夾,一般情況下flag為0,如果當後綴和input3匹配到的話,則flag為1,這樣只會輸出匹配到的後綴,如果沒有匹配到則flag仍然為0並輸出所有後綴!
function setPrompt() {
var flag = 0
var input1 = getInput()
var input2;
var input3;
if (input1.indexOf('@') === -1) {
input2 = input1
} else {
input2 = input1.slice(0, input1.indexOf('@'))
input3 = input1.slice(input1.indexOf('@') + 1)
}
var res = []
for (var i = 0; i < postfixList.length; i++) {
if (postfixList[i].indexOf(input3) === 0) {
res[res.length] = input2 + '@' + postfixList[i]
flag = 1;
}
}
if (flag === 0) {
for (var i = 0; i < postfixList.length; i++) {
res[res.length] = input2 + '@' + postfixList[i];
}
}
return res
}
最後剩下用戶點擊和按下enter的互動優化,需求為:
- 使用CSS实现:鼠标滑过提示框的某一个提示时,这个提示内容背景色变化,表示鼠标经过了这个DOM节点
- 鼠标如果点击某个提示,则提示内容进入输入框,同时提示框消失 在上个步骤结束后,
- 在输入框中任意再输入字符或删除字符,则重新开始出现提示框
function selected() {
/*if 被点击的是不是提示框中的Li节点 {
获取被点击Li对应的提示内容
将内容放到input输入框中
隐藏输入框*/
ul.onclick = function (e) {
var ev = e || window.event;
var target = ev.target || ev.srcElement;
if (target.nodeName.toUpperCase() == 'LI') {
input.value = target.innerText;
hide();
}
}
}
加上键盘
需求
我们给提示框加上3个按键的功能,分别是回车和上下键,使得可以通过键盘操作进行提示框的选择
- 当有提示框的时候,默认第一个提示为被选择状态,用一个和鼠标滑过不一样的背景色来标识
- 当有输入框的时候,按上键,可以向上移动选择状态,如果按键之前的被选择提示是第一个,则被选状态移到最下面一个
- 当有输入框的时候,按下键,可以向下移动选择状态,如果按键之前的被选择提示是最后一个,则被选状态移到第一个
- 当有输入框时,按回车键,则将当前被选中状态的提示内容,放到输入框中,并隐藏提示框 当没有输入框的时候,这3个键盘按键无响应
- 当用户输入发生改变的时候,选择状态都重新切回到第一个提示
這裡的思路有兩種方法,一種是基於dom另外一種則是,我選擇的,基於數據方式。
先設定一個index,如果觸發了下鍵,則 :
- index++,並且清除上一個的active
- 判斷index是否等於0,如果等於0則讓列表內第一個active
- 判斷index是否等於最後一個(index === lis.length),如果index在最後一個又按下了下鍵表示index要回到第一個,並讓index=0
- 如果既不是第一個也不是最後一個的狀態下,直接將index賦值即可
( lis[index].classList.add(‘active’))
如果觸發了上鍵,則 :
-
先清除 ’ 當前的index’,然後再來判斷index
-
如果判斷index等於0,則讓列表最後一個active(lis.length - 1),並且讓index的值變成列表值最後一個( index = lis.length; index–),最後index
function eventAdd() {
var index = 0;
var lisLi = null;
window.addEventListener("keyup", function (event) {
console.log(event.code);
var lis = ul.children
if (event.defaultPrevented) {
return; // Do nothing if event already handled
}
if (event.code === 'ArrowDown') {
index++;
lis[index - 1].classList.remove('active')
if (index === 0) {
lis[0].classList.add('active')
} else if (index === lis.length) {
lis[0].classList.add('active')
index = 0;
} else {
lis[index].classList.add('active')
}
}
if (event.code === 'ArrowUp') {
lis[index].classList.remove('active')
if (index === 0) {
lis[lis.length - 1].classList.add('active')
index = lis.length;
index--
} else {
lis[index - 1].classList.add('active')
index--
}
}
if (event.code === "Enter") {
input.value = lis[index].innerText;
hide();
}
if (event.code === 'Escape') input.select()
input.addEventListener("dblclick", function () {
input.select()
});
})
}