JS实现百度搜索框


Posted in Javascript onFebruary 25, 2021

本文实例为大家分享了JS实现百度搜索框的具体代码,供大家参考,具体内容如下

实现原理

向输入框动态输入时关键词,将当前关键词作为问号参数后面的值,因为要跨域使用百度的接口,所以通过 JSONP 跨域创建 Ajax 请求。回调函数处理返回值。

尝试研究了一下百度的接口,发现原生的 XHR 接口参数有点复杂(百度应该是考虑了很多情况)。

找了一个 2345 导航,在输入框随便输入一个字母 s,打开 Network,发现它也是向百度的一个地址发送了请求,其中问号后面的‘&wd=s'发送的就是此关键词,'&cb='应该就是回调处理函数,并且它的 Type 也是 script,2345 导航应该也是通过 JSONP 向百度获取数据的。

JS实现百度搜索框

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);

点开那条请求,果然在里面看到了返回的数据。返回的结果是以一个对象的形式返回的。q 对应着检索关键词,s 对应着返回的结果(数组形式)

JS实现百度搜索框

后续只需要动态创建 li 标签,设置里面的内容,以及注意其他细节问题。

1.使用 flex 布局实现搜索框的水平垂直居中。

坑 设置完 flex 属性之后发现并没有水平垂直居中,当时设置了父盒子 height:100%,发现如果将 height 设置成具体值就可以实现居中。怀疑是设置了%高度无效,查了一下,高度百分比是相对于父盒子的,也就是 body。默认 html 和 body 是没有设置 height 的。另外,在布局中对于没有设置宽高的块状盒子,宽度默认是 100%的,高度是由里面的内容自然撑开的。

2.先获取常用的 DOM 节点,避免后续频繁查询操作 DOM。

3.为了避免在输入过程中频繁发送请求(如果打字速度快),对请求函数做了函数节流,调了一下间隔 130ms 差不多正好,时间再长就会有卡顿的感觉。使用了 ES6 中的箭头函数避免了 setTimeout 中 this 指向的问题。

4.在回调函数中:

  • 每一次执行时首先要清除建议框里的内容,不然上一次的结果还会存在建议框里!截取了结果中的前五个(如果把所有结果都展示出来感觉有点丑…百度官方是展示前四个搜索建议)
  • 结果处理完毕后,执行自执行匿名函数,删除创建的 script 标签;

5.由于 li 是动态创建的,点击 li 标签或者点击"搜索一下"跳转百度进行搜索时,利用事件冒泡原理,进行事件委托。这里没有考虑兼容性问题:

e = e || window.event;
target = e.target || e.srcElement;

6.除了点击事件,键盘事件?回车键以及上下键都是进行事件委托进行注册的。

最终能够实现键盘上下键鼠标选择,点击“搜索一下”或回车键实现跳转搜索。

代码:

<!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]);
 }
 };

 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(() => {
 // 创建script标签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)
 }

 };

 // 回调函数处理返回值
 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++) {
 // 动态创建li标签
 var liObj = document.createElement("li");
 liObj.innerHTML = result[i];
 searchResult.appendChild(liObj);
 }
 // 自执行匿名函数--删除用于跨域的script标签
 (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标签或者点击搜索按钮跳转到百度搜索页面
 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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
判断目标是否是window,document,和拥有tagName的Element的代码
May 31 Javascript
TreeView 用法(有代码)(asp.net)
Jul 15 Javascript
Extjs407 getValue()和getRawValue()区别介绍
May 21 Javascript
JS在IE下缺少标识符的错误
Jul 23 Javascript
JavaScript中setUTCMilliseconds()方法的使用详解
Jun 12 Javascript
Bootstrap每天必学之工具提示(Tooltip)插件
Apr 26 Javascript
JS基于正则截取替换特定字符之间字符串操作示例
Feb 03 Javascript
jQuery实现复制到粘贴板功能
Feb 11 Javascript
Vue组件之自定义事件的功能图解
Feb 01 Javascript
原生JS实现瀑布流插件
Feb 06 Javascript
在vue 中使用 less的教程详解
Sep 26 Javascript
浅谈JS的原型和继承
May 08 Javascript
基于JavaScript实现随机点名器
Feb 25 #Javascript
JavaScript仿京东轮播图效果
Feb 25 #Javascript
Vue基本指令实例图文讲解
Feb 25 #Vue.js
使用webpack和rollup打包组件库的方法
Feb 25 #Javascript
vue常用高阶函数及综合实例
Feb 25 #Vue.js
原生JS实现音乐播放器的示例代码
Feb 25 #Javascript
详解vite2.0配置学习(typescript版本)
Feb 25 #Javascript
You might like
《星际争霸II》全新指挥官斯台特曼现已上线
2020/03/08 星际争霸
修改PHP的memory_limit限制的方法分享
2012/02/21 PHP
file_get_contents(&quot;php://input&quot;, &quot;r&quot;)实例介绍
2013/07/01 PHP
对PHP新手的一些建议(PHP学习经验总结)
2014/08/20 PHP
php把数组值转换成键的方法
2015/07/13 PHP
php命令行(cli)模式下报require 加载路径错误的解决方法
2015/11/23 PHP
PDO::commit讲解
2019/01/27 PHP
安装PHP扩展时解压官方 tgz 文件后没有configure文件无法进行配置编译的问题
2020/08/26 PHP
调试Node.JS的辅助工具(NodeWatcher)
2012/01/04 Javascript
js传参数受特殊字符影响错误的解决方法
2013/10/21 Javascript
jQuery focus和blur事件的应用详解
2014/01/26 Javascript
javascript实现数组中的内容随机输出
2015/08/11 Javascript
jQuery插件EasyUI校验规则 validatebox验证框
2015/11/29 Javascript
老生常谈ES6中的类
2017/07/31 Javascript
JavaScript轮播停留效果的实现思路
2018/05/24 Javascript
layui框架table 数据表格的方法级渲染详解
2018/08/19 Javascript
详解关于微信setData回调函数中的坑
2019/02/18 Javascript
es6 filter() 数组过滤方法总结
2019/04/03 Javascript
如何在VUE中使用vue-awesome-swiper
2021/01/04 Vue.js
简单介绍Python2.x版本中的cmp()方法的使用
2015/05/20 Python
详解Django之admin组件的使用和源码剖析
2018/05/04 Python
Django model update的多种用法介绍
2020/03/28 Python
python 利用jinja2模板生成html代码实例
2019/10/10 Python
解决Tensorboard可视化错误:不显示数据 No scalar data was found
2020/02/15 Python
python_array[0][0]与array[0,0]的区别详解
2020/02/18 Python
浅谈Django中的QueryDict元素为数组的坑
2020/03/31 Python
css3实现圆锥渐变conic-gradient效果
2020/02/12 HTML / CSS
军训自我鉴定
2013/12/14 职场文书
美发活动策划书
2014/01/14 职场文书
机械制造毕业生求职信
2014/03/03 职场文书
先进事迹材料范文
2014/12/29 职场文书
2015年外贸业务员工作总结范文
2015/05/23 职场文书
2016春季幼儿园大班开学寄语
2015/12/03 职场文书
2016党员发展对象培训心得体会
2016/01/08 职场文书
MySQL REVOKE实现删除用户权限
2021/06/18 MySQL
试用1103暨1103、1101同门大比武 [ DAIWEI ]
2022/04/05 无线电