本文實例為大家分享了JS實現(xiàn)百度搜索框的具體代碼,供大家參考,具體內(nèi)容如下
實現(xiàn)原理
向輸入框動態(tài)輸入時關(guān)鍵詞,將當(dāng)前關(guān)鍵詞作為問號參數(shù)后面的值,因為要跨域使用百度的接口,所以通過 JSONP 跨域創(chuàng)建 Ajax 請求。回調(diào)函數(shù)處理返回值。
嘗試研究了一下百度的接口,發(fā)現(xiàn)原生的 XHR 接口參數(shù)有點復(fù)雜(百度應(yīng)該是考慮了很多情況)。
找了一個 2345 導(dǎo)航,在輸入框隨便輸入一個字母 s,打開 Network,發(fā)現(xiàn)它也是向百度的一個地址發(fā)送了請求,其中問號后面的‘&wd=s'發(fā)送的就是此關(guān)鍵詞,'&cb='應(yīng)該就是回調(diào)處理函數(shù),并且它的 Type 也是 script,2345 導(dǎo)航應(yīng)該也是通過 JSONP 向百度獲取數(shù)據(jù)的。
1
2
3
4
5
6
|
var script = document.createElement( "script" ); script.src = "https://www.baidu.com/su?&wd=" + encodeURI( this .value.trim()) + "&p=3&cb=handleSuggestion" ; document.body.appendChild(script); |
點開那條請求,果然在里面看到了返回的數(shù)據(jù)。返回的結(jié)果是以一個對象的形式返回的。q 對應(yīng)著檢索關(guān)鍵詞,s 對應(yīng)著返回的結(jié)果(數(shù)組形式)
后續(xù)只需要動態(tài)創(chuàng)建 li 標(biāo)簽,設(shè)置里面的內(nèi)容,以及注意其他細(xì)節(jié)問題。
1.使用 flex 布局實現(xiàn)搜索框的水平垂直居中。
坑 設(shè)置完 flex 屬性之后發(fā)現(xiàn)并沒有水平垂直居中,當(dāng)時設(shè)置了父盒子 height:100%,發(fā)現(xiàn)如果將 height 設(shè)置成具體值就可以實現(xiàn)居中。懷疑是設(shè)置了%高度無效,查了一下,高度百分比是相對于父盒子的,也就是 body。默認(rèn) html 和 body 是沒有設(shè)置 height 的。另外,在布局中對于沒有設(shè)置寬高的塊狀盒子,寬度默認(rèn)是 100%的,高度是由里面的內(nèi)容自然撐開的。
2.先獲取常用的 DOM 節(jié)點,避免后續(xù)頻繁查詢操作 DOM。
3.為了避免在輸入過程中頻繁發(fā)送請求(如果打字速度快),對請求函數(shù)做了函數(shù)節(jié)流,調(diào)了一下間隔 130ms 差不多正好,時間再長就會有卡頓的感覺。使用了 ES6 中的箭頭函數(shù)避免了 setTimeout 中 this 指向的問題。
4.在回調(diào)函數(shù)中:
- 每一次執(zhí)行時首先要清除建議框里的內(nèi)容,不然上一次的結(jié)果還會存在建議框里!截取了結(jié)果中的前五個(如果把所有結(jié)果都展示出來感覺有點丑…百度官方是展示前四個搜索建議)
- 結(jié)果處理完畢后,執(zhí)行自執(zhí)行匿名函數(shù),刪除創(chuàng)建的 script 標(biāo)簽;
5.由于 li 是動態(tài)創(chuàng)建的,點擊 li 標(biāo)簽或者點擊"搜索一下"跳轉(zhuǎn)百度進(jìn)行搜索時,利用事件冒泡原理,進(jìn)行事件委托。這里沒有考慮兼容性問題:
1
2
|
e = e || window.event; target = e.target || e.srcElement; |
6.除了點擊事件,鍵盤事件–回車鍵以及上下鍵都是進(jìn)行事件委托進(jìn)行注冊的。
最終能夠?qū)崿F(xiàn)鍵盤上下鍵鼠標(biāo)選擇,點擊“搜索一下”或回車鍵實現(xiàn)跳轉(zhuǎn)搜索。
代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
<!DOCTYPE html> < html lang = "en" > < head > < meta charset = "UTF-8" > < meta name = "viewport" content = "width=device-width, initial-scale=1.0" > <!-- 兼容性視圖 --> < meta http-equiv = "X-UA-Compatible" content = "ie=edge" > < meta content = "更方便快捷搜索,從而達(dá)到事半功倍的效果" name = "description" > < title >search you want</ title > < style > html { height: 100%; } body { background: #f0f3ef; height: 100%; } .container { height: 100%; display: flex; justify-content: center; align-items: center; flex-direction: column; } .bgDiv { box-sizing: border-box; width: 595px; height: 55px; position: relative; /* position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); */ } .search-input-text { border: 1px solid #b6b6b6; width: 495px; background: #fff; height: 33px; line-height: 33px; font-size: 18px; padding: 3px 0 0 7px; } .search-input-button { width: 90px; height: 38px; color: #fff; font-size: 16px; letter-spacing: 3px; background: #3385ff; border: .5px solid #2d78f4; margin-left: -5px; vertical-align: top; opacity: .9; } .search-input-button:hover { opacity: 1; box-shadow: 0 1px 1px #333; cursor: pointer; } .suggest { width: 502px; position: absolute; top: 38px; border: 1px solid #999; background: #fff; display: none; } .suggest ul { list-style: none; margin: 0; padding: 0; } .suggest ul li { padding: 3px; font-size: 17px; line-height: 25px; cursor: pointer; } .suggest ul li:hover { background-color: #e5e5e5 } </ style > </ head > < body > < div class = "container" > < div class = "bgDiv" > < input type = "text" class = "search-input-text" value = "" autofocus placeholder = "關(guān)鍵詞" > < input type = "button" value = "搜索一下" class = "search-input-button" id = "btn" > < div class = "suggest" > < ul id = "search-result" > </ ul > </ div > </ div > </ div > < script > var suggestContainer = document.getElementsByClassName("suggest")[0]; var searchInput = document.getElementsByClassName("search-input-text")[0]; var bgDiv = document.getElementsByClassName("bgDiv")[0]; var searchResult = document.getElementById("search-result"); // 清除建議框內(nèi)容 function clearContent() { var size = searchResult.childNodes.length; for (var i = size - 1; i >= 0; i--) { searchResult.removeChild(searchResult.childNodes[i]); } }; var timer = null; // 注冊輸入框鍵盤抬起事件 searchInput.onkeyup = function (e) { suggestContainer.style.display = "block"; // 如果輸入框內(nèi)容為空 清除內(nèi)容且無需跨域請求 if (this.value.length === 0) { clearContent(); return; } if (this.timer) { clearTimeout(this.timer); } if (e.keyCode !== 40 && e.keyCode !== 38) { // 函數(shù)節(jié)流優(yōu)化 this.timer = setTimeout(() => { // 創(chuàng)建script標(biāo)簽JSONP跨域 var script = document.createElement("script"); script.src = "https://www.baidu.com/su?&wd=" + encodeURI(this.value.trim()) + "&p=3&cb=handleSuggestion"; document.body.appendChild(script); }, 130) } }; // 回調(diào)函數(shù)處理返回值 function handleSuggestion(res) { // 清空之前的數(shù)據(jù)!! clearContent(); var result = res.s; // 截取前五個搜索建議項 if (result.length > 4) { result = result.slice(0, 5) } for (let i = 0; i < result.length ; i++) { // 動態(tài)創(chuàng)建li標(biāo)簽 var liObj = document .createElement("li"); liObj.innerHTML = result [i]; searchResult.appendChild(liObj); } // 自執(zhí)行匿名函數(shù)--刪除用于跨域的script標(biāo)簽 (function () { var s = document .querySelectorAll('script'); for (var i = 1 , len = s .length; i < len; i++) { document.body.removeChild(s[i]); } })() } function jumpPage() { window.open(`https://www.baidu.com/s?word=${encodeURI(searchInput.value)}`); } // 事件委托 點擊li標(biāo)簽或者點擊搜索按鈕跳轉(zhuǎn)到百度搜索頁面 bgDiv.addEventListener("click", function (e) { if (e.target.nodeName.toLowerCase() === 'li') { var keywords = e.target.innerText; searchInput.value = keywords ; jumpPage(); } else if (e.target.id === 'btn') { jumpPage(); } }, false); var i = 0 ; var flag = 1 ; // 事件委托 監(jiān)聽鍵盤事件 bgDiv.addEventListener("keydown", function (e) { var size = searchResult .childNodes.length; if (e.keyCode === 13) { jumpPage(); }; // 鍵盤向下事件 if (e.keyCode === 40) { if (flag === 0) { i = i + 2; } flag = 1 ; e.preventDefault(); if (i >= size) { i = 0; } if (i < size ) { searchInput.value = searchResult .childNodes[i++].innerText; } }; // 鍵盤向上事件 if (e.keyCode === 38) { if (flag === 1) { i = i - 2; } flag = 0 ; e.preventDefault(); if (i < 0) { i = size - 1; } if (i > -1) { searchInput.value = searchResult.childNodes[i--].innerText; } }; }, false); // 點擊頁面任何其他地方 搜索結(jié)果框消失 document.onclick = () => clearContent() </ script > </ body > </ html > |
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://blog.csdn.net/rujin_shi/article/details/83657566