前言
这两天在开发一个自己的chrome插件,实现自定义新标签页,那么新标签页肯定少不了搜索的功能,因为我比较常用的搜索引擎是百度,所以会跳到百度的搜索结果,并且通过调用API来实现有一个提示的小窗口,原理是挺简单的,但是写的过程中还是遇到一些问题,记录一下。
先来看看效果图
做的不是很好看,因为目前只是把功能实现了,样式都还是测试用的。重点来讲讲功能。
实现代码
HTML代码
1 | <div class="main"> |
JS代码:
1 | <script src="./asset/font/iconfont.js"></script> |
这里主要讲一下这些功能的实现原理:
使用百度进行跳转搜索
通过给百度的url传递 wd 字段的参数就可以跳转到相应的搜索结果,就像我上面写的那样。我这里通过open方法来跳转的目的是为了在新窗口中打开。但是有一点不好的是可能会被浏览器拦截,不过这是我自用的插件所以没影响。关键字提示窗口
这里实现这个提示窗口主要是用到了jsonp向相应的API发起跨域请求(如上面代码所示),然后就可以拿到相应的数据。单击提示进行搜索
这个其实就是在拿到数据并且添加进HTML中后对每条数据进行遍历,绑定一个单击事件,单击进行相应的跳转就可以了。
大部分代码都是很好理解的,这里就不做过多的解释了
CSS代码:
1 | * { |
样式这里可以讲的一点就是如何使一个dom元素沾满整个屏幕:1
2
3
4
5
6
7
8html,
body {
height: 100%;
}
.main {
width: 100%;
height: 100%;
}
主要就是通过这些代码来实现,也非常好理解。
开发过程中我遇到的一些问题以及解决办法
click 和 blur 事件的冲突
起初当我基本上完成大部分功能的之后进行测试,发现当点击提示框中的内容的时候竟然没有进行跳转,而是直接执行了失焦事件中的隐藏提示框的代码。我就猜想应该是由于单击的时候会使文本框失焦,并且 blur 会在 click 之前触发,进行一些尝试之后还是没有解决问题,后来百度了一下找到了解决问题的两种办法:
第一种就是通过设置定时器,通过设置
setTimeout
来使 blur 事件中的代码晚一些执行:1
2
3
4
5searchInput.blur(function () {
setTimeout(function () {
searchTips.hide();
}, 300)
})但是这种办法的缺点也很明显,就是延迟的时间要足够长,起码要长到 click 事件的代码执行完毕,我这里测试大概最少300ms,所以在执行 blur 事件的时候能感觉到很明显的延迟,体验并不是很好。
第二种就是使用 mousedown事件来替代 click 事件:
我这里采用的就是这种方式,这种方式就很好的解决了问题,但是也不是没有缺点, mousedown 事件在鼠标按下时就会触发,所以触发次数也就和按下的事件有关系,如果只是快速的按一下那么没有区别,但是按久了就会触发非常多次,所以很多场景下不适用,不过我这里没有关系,因为只要按下去了就打开新窗口不在当前window环境下了,所以没有影响。这里再来讲一下 mousedown、mouseup、click这三个事件的主要区别及应用场景:
click :在同一元素上 相继触发 mousedown 和 mouseup 才会触发 click ,并且能够通过按下回车来触发。大部分场景下都是使用 click ,因为过程比较完整也不会重复触发。经测试右键不会触发。
mouseup :释放鼠标时触发。右键可以触发。
mousedown:鼠标按下时触发。不过由于按下就触发的特性,比较的快,所以 mousedown 会在 blur 之前触发,这就是为什么使用 mousedown 可以解决冲突问题。
这里总结一下:一次完整的鼠标单击就是这样一个过程 mousedown > mouseup > click 。 mousedown 和 mouseup 配合可以实现监听鼠标长按。具体怎么使用就看场景需求了。
异步问题
当我完成了添加提示框功能之后,想要继续完成鼠标经过提示内容给其添加样式的功能,当我写完之后却发现了问题:我是直接将添加样式的代码放在了和文本框平级,我想这从逻辑上来说应该没有什么问题,但实际上却出现了问题,起初是报错提示框内容中的那个jQuery对象是空的,这就很奇怪了,我明明在每次的 input 事件执行时就给这个jQuery对象赋值了,出现这种情况也就意味着input事件发生在添加样式之后。
经过一段事件的思考我想明白了,主要是忽略了无论是 input 事件还是 Ajax 的请求,这二者都是异步的任务,而添加样式所用的过程是主线程上的同步操作,所以一定会在这两个异步任务之前生效,所以才会导致这种情况的出现,那么解决办法也就很简单了,将添加样式的代码在这两个异步任务之后执行就可以了,所以只需要将代码放进 Ajax 的回调中执行就可以了,那么这样就成功的解决了问题。同理,单击提示进行搜索的那部分代码也是一样的道理。
其后后面也有一部分代码(通过方向键控制要搜索的内容的那部分)涉及到操作提示框内容的jQuery对象,那为什么不会出现这种情况呢,到这里其实也很好理解了,因为这部分的代码也是由事件来触发的,也是异步的,并且是在最后面,所以一定是最后执行的。
关于异步单线程可以参考我的这篇文章:简单理解js单线程异步与事件循环机制
阻止键盘方向键的默认行为
在文本框中,键盘的方向键存在着默认行为,比如说是方向键上,这会使光标移动到文本框最前面,我们在搜索的提示框中就可以通过上下键来切换搜索内容,但是同时也会触发默认行为,使光标移动到文本框最前端,这样的结果很明显不是我们想要的。
百度了一下相关的解决办法,就是阻止上箭头的默认行为,但是发现好像不起作用,最后其实发现解决办法是和解决 click 和 blur 冲突问题的办法类似,更换触发事件,将按下的keyup事件修改为keydown事件,然后这时候阻止默认行为就有效了,应该也是触发先后的问题,这样修改之后发生的另一个变化就是按键可以”连发”了,不过这也不算坏处。
总结
通过制作这个简单的搜索小功能还是收获挺多的,能够完全理解的话也能进步挺多的,特别是异步问题那里,之前只有其概念,现在运用起来了。