vue輸入框聯想詞功能

1.實現的功能

輸入框輸入字符後,聯想詞列表出現,能夠按「↓」或「↑」選擇列表中的內容,也能夠鼠標點選,且互相不影響選擇樣式,即只會出現一個被選中,「Enter」鍵發起檢索。javascript

2.DOM結構

<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>複製代碼

3.變量

content: '',---雙向綁定的數據,input輸入框中的內容,用戶選擇聯想詞列表時同步變化
inputContent: '',---保存用戶經過鍵盤輸入的內容,不與用戶選擇的聯想詞列表同步變化
focusIndex: 0,---用戶選擇的聯想詞<li>列表的下標
associateWords: [],---聯想詞列表數組
showList: true---是否顯示聯想詞列表由此變量和associateWords的長度共同控制

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

4.JavaScript部分

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) 
    })    
}複製代碼
相關文章
相關標籤/搜索