輸入框輸入字符後,聯想詞列表出現,能夠按「↓」或「↑」選擇列表中的內容,也能夠鼠標點選,且互相不影響選擇樣式,即只會出現一個被選中,「Enter」鍵發起檢索。javascript
<template> <div class="input-m"> <div class="search"> <input type="text" :placeholder=placeholder v-model="content" @keyup="input"> </div> <ul class="associate-list" v-show="associateWords&&showList" @mouseout="selectedLi(0)"> <li class="associate-item">{{inputContent}}</li> <li class="associate-item" v-for="(item,index) of associateWords" :key="index" @mouseover="selectedLi(index+1)">{{item}}</li> </ul> </div> </template>複製代碼
inputConent是用於記錄用戶經過鍵盤輸入的內容,經過上下鍵選擇或鼠標懸浮時選擇的會經過雙向綁定同步到content中,以百度搜索聯想詞列表爲例,當用戶一直按向下鍵時,超過聯想詞列表後,input框中的內容爲用戶最開始輸入的內容。html
focusIndex記錄用戶選擇的<li>標籤的下標,當一直按向上或向下鍵時,會出現focusIndex超出<li>列表長度的或小於0的清理,用focusIndex = (focusIndex+length)%length操做,能夠實現fousIndex老是在0至length-1範圍內。java
當經過document.getElementsByClassName獲取<li>數組時,數組下標從0開始,而foucusIndex初始值爲0,當按下「↓」時,focusIndex+1,選中的就是<li>列表的下標爲1的元素,即第2個<li>,這是不合理的。node
若是將focusIndex的下標初始值設爲-1,知足了上邊的需求。那麼當按下「↑」時,focusIndex-1,經過取餘操做能夠獲得foucusIndex = length-2,即<li>列表的倒數第2項,也是不合理的。ios
故將用戶輸入的文字內容做爲<li>列表的第一項,且隱藏,將focusIndex初始值設爲0。這樣就實現了按上下鍵選擇,且超出顯示的長度時,是用戶經過鍵盤輸入的內容。json
用showList與associateWords一塊兒控制列表的顯示,沒有相關聯想詞時確定不顯示,但用戶點擊輸入框之外的位置時,聯想詞列表應該能夠隱藏。若是採用將associateWords來隱藏的話,用戶再次點擊輸入框時,會多向服務器發送一次搜索相關聯想詞的請求。axios
input (e) {
//keyup事件的event
e = e || window.event
this.showList = true
// 按「↑」 鍵
if (e.keyCode === 38) {
this.focusIndex--
this.selectedLi()
} else if (e.keyCode === 40) {
// 按「↓」,數組下標從0開始,list的[0]項內容爲用戶輸入內容,不顯示,從[1]項開始顯示
this.focusIndex++
this.selectedLi()
} else if (e.keyCode === 13) {
// 按「Enter」調用搜索函數
this.doSomething() //----向後臺發送搜索請求
this.associateWords = []
} else {
// 用戶繼續輸入時,將inputContent置空----很是重要的一步
this.inputContent = ''
this.focusIndex = 0
// 搜索聯想內容
this.getAssociateWords() //----向後臺請求相關聯想詞列表
this.clearSelected()
}
}複製代碼
與樣式相關的js操做數組
selectedLi (hoverIndex) {
// 當inputContent內容爲空時,記錄下搜索框中用戶輸入的內容,做爲associate-item的第一項
if (this.inputContent === '') {
this.inputContent = this.content
}
let associateList = document.getElementsByClassName('associate-item')
// 移除已添加的.selected樣式
for (var i = 0; i < associateList.length; i++) {
associateList[i].classList.remove('selected')
}
if (hoverIndex !== undefined) {
this.focusIndex = hoverIndex
}
// 一直按向下鍵超出聯想內容li長度時,應回到聯想內容第一個
this.focusIndex = (this.focusIndex + associateList.length) % associateList.length
// 爲選中的li添加.selected樣式
let selectedOne = associateList[this.focusIndex]
this.content = selectedOne.textContent
selectedOne.classList.add('selected')
}
clearSelected () {
let associateList = document.getElementsByClassName('associate-item')
// 移除已添加的.selected樣式
for (var i = 1; i < associateList.length; i++) {
associateList[i].classList.remove('selected')
}
}複製代碼
爲除了input框之外的頁面部分添加監聽事件,點擊input之外的部分時,隱藏聯想詞列表服務器
// 點擊input輸入框之外的位置時 隱藏聯想詞列表
document.body.addEventListener('click', e => {
if (e.target.nodeName === 'INPUT') {
this.showList = true
} else {
this.showList = false
}
})複製代碼
向後臺服務器請求聯想詞列表函數
getAssociateWords () {
let self = this
axios.get('XX/data.json').then(function (res) {
self.associateWords = result.slice(0, 5)
})
}複製代碼