前言 正则表达式是匹配模式,要么匹配字符,要么匹配位置。关于正则表达式的原理和写法,网上的文章已经特别之多了,本篇文章将不着重于原理与方法,将直接以各种题目的形式来进行正则表达式的介绍,同样,题目的难度也将由弱至强。首先附上经典的正则链接网站:regulex 。
基本符号
字符组
用于纵向模糊匹配,[]组内代表一个字符元素
^
在第一位放脱字符,表示求反的概念
\d
[0-9],digit,表示一位数字
\D
[^0-9],表示除数字外的任意字符
\w
[0-9a-zA-Z],word,表示数字、大小写字母和下划线等单词字母
\W
[^0-9a-zA-Z],表示非单词字母
\s
[\t\v\n\r\f],space,表示空白格,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符
\S
[^ \t\v\n\r\f],表示非空白符
.
[^\n\r\u2028\u2029],通配符,表示几乎任意字符,换行、回车、行分隔、段分隔符除外。
\1
反向引用,代表第一个用括号区分的分组,括号嵌套的号由开括号(来判断
量词
用于横向匹配,匹配多个字符,默认为贪婪匹配,可后加?变为惰性匹配
{m,}
表示至少出现m次
?
等价于{0,1},表示出现或不出现
+
等价于{1,},表示出现至少一次
*
等价于{0,},表示出现任意次或者不出现
位置特性
用于位置方式的匹配
^、$
脱字符、美元符号分别在多行匹配中,匹配行开头与行结尾
\b
匹配单词边界,具体就是\w与\W之间的位置,也包括\w与^、$之间的
\B
同样,是\b的反面的意思
(?=p)
p为一个子模式,即匹配p前面的位置
(?!p)
其实就是(?=p)取反,除了p前面的位置以外的所有位置
方法
返回值与参数
test
一个在字符串中测试是否匹配的RegExp方法,它返回true或false。regex.test(string)
exec
一个在字符串中执行查找匹配的RegExp方法,它返回一个数组(未匹配到则返回null)regex.exec(string)
match
一个在字符串中执行查找匹配的String方法,它返回一个数组或者在未匹配到时返回null。string.match(regex);match返回的是一个数组,包括各个括号匹配的内容
search
一个在字符串中测试匹配的String方法,它返回匹配到的位置索引,或者在失败时返回-1。
replace
个在字符串中执行查找匹配的String方法,并且使用替换字符串替换掉匹配到的子字符串。string.replace(regex, “ ”)
split
一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的String方法。
简单正则匹配 字符匹配 16进制颜色值 要求匹配:#12f3a1,#ffBabd,#FFF;等颜色值字母不区分大小写,且可为3位或者六位
1 2 3 let regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g ;let string = "#12f3a1 #ffBabd #FFF #123 #586" ;console .log(string.match(regex));
相当简单的正则,主要就是把基础知识运用下,只有两个分支匹配且逻辑清楚。
24小时时间 要求匹配:23:59,04:09,8:9,19:47;这样的时间,前面的0可以省略也可带着
1 2 3 4 5 6 7 8 let regex = /^(0?[0-9]|1[0-9]|2[0-3]):(0?[0-9]|[1-5][0-9])$/ ;let arr = ["23:59" , "04:09" , "8,9" , "19:47" ];let res = [];for (let i = 0 ; i < arr.length; i++) { if (regex.test(arr[i])) { res.push(arr[i]); } }
也是比较简单的正则,记得用括号将各段隔开,不然运算顺序可能不与你想的一致。
IP地址 要求匹配:192.168.225.255,156.234.156.215,1.2.3.4;类似的IP地址
1 2 3 4 5 6 7 8 let regex = /^(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.\1\.\1\.\1$/ ;let arr = ["192.168.225.255" , "156.234.156.215" , "1.2.3.4" ];let res = [];for (let i = 0 ; i < arr.length; i++) { if (regex.test(arr[i])) { res.push(arr[i]); } }
这里的.字符需要转义,且利用括号分组来复用前面的正则。\1代表第一个括号引用的分组,根据第一个开括号(来确认。
带格式日期 要求匹配:2020-09-12,2043-12-30,2018/08/09,2016.06.21;分隔符有三种可用,且要求分隔符前后使用一样。
1 2 3 4 5 6 7 8 let regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/ ;let res = [];let arr = ["2020-09-12" ,"2043-12-30" ,"2018/08/09" ,"2016.06.21" ];for (let i = 0 ; i < arr.length; i++) { if (regex.test(arr[i])) { res.push(arr[i]); } }
要求分隔符前后一致,因此我们就必须用上题提过的括号分组复用,才能够实现这样的功能。我这里没有对日期的期限进行要求,直接用的数字均可,有要求的话,根据之前IP例题的逻辑,也能够很容易写出,这里就不再赘述。
同样,分组复用可以实现简单的替换,例如:想把yyyy-mm-dd替换成mm/dd/yyyy,以下的代码可以实现
1 2 3 4 5 6 let regex = /(\d{4})-(\d{2})-(\d{2})/ ;let string = "2020-09-12" ;let res = string.replace(regex, function ( ) { return RegExp .$2 + "/" + RegExp .$3 + "/" + RegExp .$1 ; });
字符串去重 实例:将”aaaaabbbbbccccc”去重返回成为”abc”。利用括号分组的同样匹配,来实现查询出重复字符的效果,由于重复字符可以出现多次,因此后面还要加上+,表示至少出现一次。
1 2 3 4 let regex = /(\w)\1+/g ;let str = "aaaaabbbbbddddggggggggffff" ;let res = str.replace(regex, "$1" );
HTML标签 要求匹配HTML标签a内容,比如”“” “,即匹配出两个<>之间,且第一个字符为a
这里的^脱字符代表取反,即除了”>”以外均匹配。
驼峰字符串 要求将一个连续字符串如:get-element-by-id转化成驼峰形式
1 2 3 function toHump (str ) { return str.replace(/-(\w)/g , function ($1 )) }
将-后面是字符的-与首字符的位置均匹配到,然后将$1,即-后的字符变成大写后replace进去
邮箱格式 1.不限制长度
2.不限制大小写
3.邮箱开头必须是数字或字符串
4.邮箱中可以使用字母、数字、点号、下划线、减号,但是不能连写点号、下划线、减号,如 abc_-de@q_.q.com
5.@符号前后不能为点号、下划线、减号
1 2 3 4 function isAvailableEmail (sEmail ) { let reg = /^([\w+\._-])+@\w+[\.\w]+$/ ; return reg.test(sEmail); }
识别十进制整数 修改 js 代码中 parseInt 的调用方式,使之通过全部测试用例。
eg:’12px’、’0x12’
1 2 3 4 5 6 7 8 9 function parse2Int (num ) { var regex=/^\d+/ ; num=regex.exec(num)[0 ]; return parseInt (num); }; function parse2Int (num ) { return parseInt (num,10 ); }
颜色字符串转换 考的知识点两个:
正则表达式匹配;
toString(16)转换进制;toString()可用于转换进制、判断引用类型。
做的过程中注意:
数值超界(0-255)
不足两位补零
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function rgb2hex (sRGB ) { let reg = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/ ; let res = sRGB.match(reg); if (!res) { return sRGB; } else { let str = '#' ; for (let i = 1 ; i <= 3 ; i++) { let num = parseInt (res[i]); if (num <= 255 && num >= 0 ) { str += (num < 16 ? '0' + num.toString(16 ) : num.toString(16 )); } else { return sRGB; } } return str; } }
变为驼峰 replace() 方法返回一个由替换值(replacement)替换一些或所有匹配的模式(pattern)后的新字符串。
这个用法的本质就是:对str使用RegArg做match()匹配,如果匹配到多项结果(比如使用了全局匹配g,或者分组),那么每一个匹配结果都将执行一次FuncArg函数,并且用该函数的返回值替代源字符串中的匹配项。
第一个参数可以是字符串或正则表达式,如果提供的是字符串,只会替换第一个子字符串。如果想替换所有子字符串,需要提供一个指定了 g 的正则表达式。
第二个参数可以是字符串或函数。如果是字符串,可以使用一些特殊的 字符序列 :
如果第二个参数也可以是函数,这个函数接收多个参数:function (match[,p1, p2, …, pn], offset, string)
match:匹配的子串,等同于前面提到的 $&
p1-p2:为捕获组对应的匹配字符串(如果设置了捕获组)。
offset:模式匹配项位于输入字符串的位置
string:输入的原始字符串。
函数的返回值:返回值即为替换的文本。
css 中经常有类似 background-image 这种通过 - 连接的字符,通过 javascript 设置样式的时候需要将这种样式转换成 backgroundImage 驼峰格式,请完成此转换功能
1、以 - 为分隔符,将第二个起的非空单词首字母转为大写
2、-webkit-border-image 转换后的结果为 webkitBorderImage
1 2 3 4 5 6 7 8 9 function cssStyle2DomStyle (sName ) { let reg = /-(\w)/g ; let res = sName.replace(reg, function (fullMatch, g1, index ) { if (index === 0 ) return g1; return g1.toUpperCase(); }); return res; }
获取url中参数
指定参数名称,返回该参数的值 或者 空字符串
不指定参数名称,返回全部的参数对象 或者 {}
如果存在多个同名参数,则返回数组
例:输入:http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key;输出:[1, 2, 3]
方法一:使用字符串拼接来匹配。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function getUrlParam (sUrl, sKey ) { var left= sUrl.indexOf("?" ) + 1 var right= sUrl.lastIndexOf("#" ) var parasString = sUrl.slice(left, right) var paras = parasString.split('&' ); var parasjson = {} paras.forEach(function (value, index, arr ) { var a = value.split('=' ); parasjson[a[0 ]] !== undefined ? parasjson[a[0 ]] = [].concat(parasjson[a[0 ]], a[1 ]) : parasjson[a[0 ]] = a[1 ]; }); let result = arguments [1 ] !== void 0 ? (parasjson[arguments [1 ]] || '' ) : parasjson; return result }
方法二:使用正则中的replace进行替换
1 2 3 4 5 6 7 8 9 function getUrlParam2 (sUrl, sKey ) { var result, Oparam = {}; sUrl.replace(/[\?&]?(\w+)=(\w+)/g , function ($0 , $1 , $2 ) console .log ('$0:' + $0 + " $1:" + $1 + " $2:" + $2 ); Oparam[$1] === void 0 ? Oparam[$1] = $2 : Oparam[$1] = [].concat(Oparam[$1], $2); }); sKey === void 0 || sKey === '' ? result = Oparam : result = Oparam[sKey] || '' ; return result; }
方法三:使用正则中的exec方法
1 2 3 4 5 6 7 8 9 10 11 function getUrlParam3 (sUrl, sKey ) { var resObj = {}; var reg = /(\w+)=(\w+)/g ; while (reg.exec(sUrl)) { resObj[RegExp .$1 ] ? resObj[RegExp .$1 ] = [].concat(resObj[RegExp .$1 ], RegExp .$2 ) : resObj[RegExp .$1 ] = RegExp .$2 ; } if (sKey) { return (resObj[sKey] ? resObj[sKey] : '' ); } return resObj; }
域名解析 函数parseUrl实现将一段url字段解析为Object,例如url为:”http://www.xiyanghui.com/product/list?id=123456&sort=discount#title";parseUrl(url)返回的结果为object如下:
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 let object = { protocol:"http" , host:"www.xiyanghui.com" , path:"product/list" , query: { id:"123456" , sort:"discount" }, hash:"title" } function parseUrl (str ) { if (str) { var obj = {}; var queryArr = []; var re = /^(http[s]?):\/\/([0-9a-zA-Z\.]+)\/([a-zA-Z0-9\/]+)\?([a-zA-Z0-9\=\&]+)#([0-9a-zA-Z\.]+)$/ ; var reArr = re.exec(str); if (reArr) { obj.peotocol = reArr[1 ]; obj.host = reArr[2 ]; obj.path = reArr[3 ]; queryArr = reArr[4 ].split(/[\&\=]+/ ); obj.query = {}; for (var i = 0 ; i < queryArr.length; i += 2 ) { obj.query[queryArr[i]] = queryArr[i + 1 ]; } obj.hash = reArr[5 ] return obj; } else { return null ; } } else { return null ; } }
位置匹配 千位分隔符 千位分隔符的关键在于两点:1、使用量词+多次匹配d{3};2、要求匹配的位置不能是开头,因此用(?!^)
1 2 3 4 let regex = /(?!^)(?=(\d{3})+$)/g ;let regex = /(?!^)(?=(\d{3})+$)/g ;let string = "123456789" ;let res = string.replace(regex, ',' );
如果还要求支持”12345783 23498237489 3219482”这样多个数字间用空格来区分的输入的话,只需要将^、$进行修改,改成\b,从而匹配多个连续字符的开头、结尾,而不是匹配整个字符串的开头、结尾。
1 2 3 let regex = /(?!\b)(?=(\d{3})+\b)/g ;let string = "12345783 23498237489 3219482" ;let res = string.replace(regex, ',' );
密码判断 多种条件的密码判断往往写成多个小的正则进行判断,下面基本使用三个小的条件进行密码判断。总的要求是:密码长度6-12位,由数字、小写字符、大写字符组成,但必须至少包括2种字符,且必须包含数字
1 2 3 4 5 6 7 8 9 10 11 12 13 let regex1 = /^[0-9A-Za-z]{6,12}$/ ;let regex2 = /?=.*[0-9]/ ;let regex3 = /(?=.*[0-9])(?=.*[a-z])/ ;let arr = ["192.168.225.255" , "156.234.156.215" , "1.2.3.4" ];let res = [];for (let i = 0 ; i < arr.length; i++) { if (regex1.test(arr[i]) && regex2.test(arr[i]) && regex3.test(arr[i])) { res.push(arr[i]); } }
替代正则 并不是所有的问题均适合使用正则解决:1、有些看似简单的问题,但正则做不到;2、有些能用字符串简单API就能解决的问题,使用正则会提高时间负杂度。
提取年月日 1 2 3 4 5 6 7 8 9 10 11 12 let string = "2020-09-01" ;let regex = /^(\d{4})-(\d{2})-(\d{2})/ ;console .log(string.match(regex));let string = "2020-09-01" ;let res = string.split("-" );console .log(res);
模糊查询 需要实现的功能是类似百度搜索框的模糊查询,这里先只考虑JS代码,构建的函数传入参数有2个,分别是list存储所有关键词信息的数组、keyword模糊查询的关键词、res查询得出的结果。
indexOf方法 stringObject.indexOf(searchValue)该方法从头到尾检索字符串stringObject,看它是否含有子串searchValue,开始检索得位置在字符串的开头,找到searchValue时,则返回其第一次出现的位置,没有找到则返回-1。
1 2 3 4 5 6 7 8 9 function fuzzyQuery (list, keyWord ) { let res = []; for (let i = 0 ; i < list.length; i++) { if (list[i].indexOf(keyWord) >= 0 ) { res.push(list[i]); } } return res; }
split方法 stringObject.split(separator)。该方法通过在separator指定的边界处将字符串stringObject分割成子串并返回子串数组。返回的数组中的字串不包括separator自身。如果stringObject中不存在separator,将返回一个只包含stringObject的数组。故可以根据返回数组的长度来判断是否存在子字符串separator
1 2 3 4 5 6 7 8 9 function fuzzyQuery (list, keyWord ) { let res = []; for (let i = 0 ; i < list.length; i++) { if (list[i].split(keyWord).length > 1 ) { res.push(list[i]); } } return res; }
match方法 该方法在字符串内检索指定的值,或找到一个或多个正则表达式的匹配;如果没有找到任何匹配的文本,将返回null。否则,将返回一个数组。
1 2 3 4 5 6 7 8 9 function fuzzyQuery (list, keyWord ) { let res = []; for (let i = 0 ; i < list.length; i++) { if (list[i].match(keyWord) != null ) { res.push(list[i]); } } return res; }
test方法 1 2 3 4 5 6 7 8 9 10 function fuzzyQuery (list, keyWord ) { let reg = new RegExp (keyWord); let res = []; for (let i = 0 ; i < list.length; i++) { if (reg.test(list[i])) { res.push(list[i]); } } return res; }
搜索框模糊查询实现 简单html实现 主要关注html实现,就不用上述定义的函数了,而是用更简单的方式。
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 <!DOCTYPE html > <html > <head > <meta http-equiv ="Content-Type" content ="text/html; charset=utf-8" /> <title > </title > <script type ="text/javascript" > onload = function ( ) { function handle ( ) { var keyWords = { "a" : ["abada" , "asdkasdfda" , "askfdlf" ], "b" : ["bfsdifdpa" , "杨振宇" , "杨过" ], "c" : ["cdfdfgd" , "cgfhjf" , "cuyjk" ], "d" :["dfdgd" ,"dyjhfh" ,"dhyjgh" ] }; if (keyWords[this .value]) { if (document .getElementById('dv' )) { document .body.removeChild(document .getElementById('dv' )); } var dvObj = document .createElement('div' ); dvObj.id = 'dv' ; dvObj.style.width = '300px' ; dvObj.style.border = '1px solid red' ; document .body.appendChild(dvObj); dvObj.style.position = 'absolute' ; dvObj.style.left = this .offsetLeft + 'px' ; dvObj.style.top = this .offsetHeight + this .offsetTop + 'px' ; for (var i = 0 ; i < keyWords[this .value].length; i++) { var pObj = document .createElement('p' ); pObj.innerText = keyWords[this .value][i]; pObj.style.cursor = 'pointer' ; pObj.style.margin = '5px' ; pObj.onmouseover = function ( ) { this .style.backgroundColor = 'red' ; }; pObj.onmouseout = function ( ) { this .style.backgroundColor = '' ; } dvObj.appendChild(pObj); } } } if (/msie/i .test(navigator.userAgent)) { document .getElementById('txt' ).onpropertychange = handle } else { document .getElementById('txt' ).addEventListener("input" , handle, false ); } }; </script > </head > <body > <span id ="msg" > </span > 请输入搜索关键字 <input type ="text" name ="name" value ="" style ="width:300px;height:30px;font-size:25px; border:1px solid green" id ="txt" /> 百度一下</body > </html >
利用JSONP调用百度接口 JSONP(JSONwith Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。 该代码实现搬运自CSDN
实现原理:向输入框动态输入时关键词,将当前关键词作为问号参数后面的值,因为要跨域使用百度的接口,所以通过 JSONP 跨域创建 Ajax 请求。回调函数处理返回值。
1.使用 flex 布局实现搜索框的水平垂直居中。
2.先获取常用的 DOM 节点,避免后续频繁查询操作 DOM。
3.为了避免在输入过程中频繁发送请求(如果打字速度快),对请求函数做了函数节流,调了一下间隔 130ms 差不多正好,时间再长就会有卡顿的感觉。使用了 ES6 中的箭头函数避免了setTimeout 中 this 指向的问题。
4.在回调函数中:
每一次执行时首先要清除建议框里的内容,不然上一次的结果还会存在建议框里!截取了结果中的前五个(如果把所有结果都展示出来感觉有点丑…百度官方是展示前四个搜索建议)
结果处理完毕后,执行自执行匿名函数,删除创建的 script 标签;
5.由于 li 是动态创建的,点击 li 标签或者点击”搜索一下”跳转百度进行搜索时,利用事件冒泡原理,进行事件委托。这里没有考虑兼容性问题:
6.除了点击事件,键盘事件–回车键以及上下键都是进行事件委托进行注册的。最终能够实现键盘上下键鼠标选择,点击“搜索一下”或回车键实现跳转搜索。
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 <!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 ="更方便快捷搜索,从而达到事半功倍的效果" 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 ="关键词" > <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" ); function clearContent ( ) { var size = searchResult.childNodes.length; for (var i = size - 1 ; i >= 0 ; i--) { searchResult.removeChild(searchResult.childNodes[i]); } }; function handleSuggestion (res ) { clearContent(); var result = res.s; if (result.length > 4) { result = result.slice(0, 5) } for (let i = 0 ; i < result.length; i++) { var liObj = document .createElement("li" ); liObj.innerHTML = result[i]; searchResult.appendChild(liObj); } (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)} ` ); } var timer = null ; searchInput.onkeyup = function (e ) { suggestContainer.style.display = "block" ; if (this .value.length === 0 ) { clearContent(); return ; } if (this .timer) { clearTimeout (this .timer); } if (e.keyCode !== 40 && e.keyCode !== 38) { this .timer = setTimeout (() => { 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) } }; 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 ; 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 ); document .onclick = () => clearContent() </script > </body > </html >