背景:
制作一個類似百度輸入法的智能提示框,
其中當關鍵詞輸入進來時,會有智能提示展開,實際需求是當點擊智能提示框的漢字時,輸入框中自動補全並關閉智能提示,
當點擊其他區域時,智能提示框自動隱藏,如下所示:
分析:點擊用onclick事件觸發獲取的值,然后點擊外框用失去焦點的方式解決
但實際出現效果是:
如果添加了失去焦點的方法,點擊提示文本的時候,文字也會因為輸入框失去焦點而被隱藏,以至於文字無法被選中上去:
問題出現時用方法如下:
//oA是智能提示框的列表中的單個文字 oA.onclick = function(){ populateModel(this) }; // 點擊提示文本,獲取文本並填充到輸入款中(wd是輸入框) function populateModel(cell) { wd.value = cell.firstChild.nodeValue; clearModels();//清除自動完成行 } //填充后清除提示 function clearModels() { while (oUl.childNodes.length > 0) { oUl.removeChild(oUl.firstChild); } oLi.style.border = "none"; } // 失去焦點隱藏 其中輸入框中有屬性:onblur="upperCase()",其中oUI 是智能提示的區域 function upperCase() { oUl.style.display = 'none'; }
解決方案: 這里不得不先講下鼠標點擊事件
鼠標事件
屬性 | 描述 | DOM |
---|---|---|
onclick | 當用戶點擊某個對象時調用的事件句柄。 | 2 |
oncontextmenu | 在用戶點擊鼠標右鍵打開上下文菜單時觸發 | |
ondblclick | 當用戶雙擊某個對象時調用的事件句柄。 | 2 |
onmousedown | 鼠標按鈕被按下。 | 2 |
onmouseenter | 當鼠標指針移動到元素上時觸發。 | 2 |
onmouseleave | 當鼠標指針移出元素時觸發 | 2 |
onmousemove | 鼠標被移動。 | 2 |
onmouseover | 鼠標移到某元素之上。 | 2 |
onmouseout | 鼠標從某元素移開。 | 2 |
onmouseup | 鼠標按鍵被松開。 |
鼠標點擊點擊過程是先按下鼠標(mousedown)然后彈起來(mouseup),這一過程才觸發了click事件,當click觸發之前,也就是mouseup時,blur已經先觸發失去焦點,
因此,當你點擊提示框文字時,並沒有觸發到click事件而是因為失去了焦點而提示框提前被隱藏掉了;
所以綜上分析,解決方法有兩種
1 將文字被選中這一事件用mousedown來監聽,當鼠標按下時,就將文字先選中,然后彈起來時再自動觸發onblur事件隱藏提示框中內容:
代碼如下:
oA.onmousedown = function(){ populateModel(this) };//修改了onclick改為onmousedown,其他均不變;
2另一種方式就是,不用失去焦點的方式來隱藏DOM,而是用鼠標移出提示框區域時,觸發mouseseleave事件來隱藏DOM
代碼如下:
oA.onclick = function(){ populateModel(this) };//仍然使用onclick事件觸發文字獲取 oUl.onmouseleave = function(){ oUl.style.display = 'none'; }// 當鼠標移除提示框之外后,自動隱藏
完整的百度智能輸入法提示的JS代碼:
<body>
<input type="text" id="wd" name="username" onblur="upperCase()" autocomplete="off" >
<ul id="list"></ul>
</body>
<script> var wd = document.getElementById('wd'); var oUl = document.getElementById('list'); wd.oninput = debounce(getUserAction, 100, false); function debounce(func, wait, immediate) { var timer = null; var result; var debounced = function () { var _this = this; var argu = arguments; clearTimeout(timer); if (immediate) { if (!timer) func.apply(_this, argu); timer = setTimeout(function () { timer = null; }, wait) } else { timer = setTimeout(function () { func.apply(_this, argu); }, wait) } return result; } debounced.cancel = function () { clearTimeout(timer); timer = null; } return debounced; } function getUserAction() { if (wd.value) { var oScript = document.createElement('script'); oScript.src = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=' + wd.value + '&cb=doJson'; document.body.appendChild(oScript); document.body.removeChild(oScript); } else { oUl.style.display = 'none'; } } function doJson(data) { var dataList = data.s; oUl.innerHTML = ''; if (dataList.length == 0) { oUl.style.display = 'none'; } else { dataList.forEach(function (item, index) { var oLi = document.createElement('li'); var oA = document.createElement('a'); oA.onmousedown = function(){ populateModel(this) };//單擊oA是的方法為populateModel // oA.onclick = function(){ populateModel(this) };//單擊oA是的方法為populateModel // oUl.onmouseleave = function(){ oUl.style.display = 'none'; } oA.innerText = item; oLi.appendChild(oA); oUl.appendChild(oLi); oUl.style.display = 'block'; }) } } function populateModel(cell) { wd.value = cell.firstChild.nodeValue; clearModels();//清除自動完成行 } function clearModels() { while (oUl.childNodes.length > 0) { oUl.removeChild(oUl.firstChild); } oLi.style.border = "none"; } // 失去焦點隱藏 function upperCase() { oUl.style.display = 'none'; } </script>