提示的实现(及Hack Google)
在Google/百度的搜索输入框输入内容时, 只要你的网速够快, 那么你就会看到, 在输入内容的同时, 输入框下方会弹出一个提示框, 内有n条关联内容, 所谓关联, 就是你正在输入的内容的相关信息. 比如, 你输入"香港"二字后, 还未输入后继内容, 提示框就会自动弹出并包含诸如"香港旅游" "香港酒店"这些信息.
这些信息从何而来? 简单的说, 来自搜索服务商的数据库, 它首先拿取你正在输入的内容, 然后在自己的数据库内查找这些内容, 将其中人气最旺, 数量最多的那些记录返回给你, 这么做的理由是, 既然这些记录受到较多关注, 那么自然地也很可能受到你的关注, 因此推荐给你, 反之, 冷门的,相关记录数量少的, 就不会推荐给你.
假设你是一位站长, 为网站用户提供某一项服务, 其中, 需要用户输入某些内容, 而你就打算实现上述的自动提示功能, 即, 在用户在输入过程中提供相关的提示.
现在要做的, 就是如何实现这一个功能.
过程并不复杂, 四个部分:
检测用户当前输入的内容.
将用户输入的内容发送给服务商.
将服务商提供的数据返回给用户.
如果用户激活(比如点击或者按下回车键)其中某一条关联, 则将其作为用户的输入内容.
先说其中第二项: 如何向服务商发出内容 ? 我推荐Google Suggest, 它的使用很简单: 发出一个JavaScript调用请求, 如下:
<script type='text/javascript' src=...></script>
其中的src地址是:
http://www.google.com/complete/search?client=suggest&hl=zh-CN&js=true&qu=
请注意, 其中参数qu的值就是用户输入的内容.
因此, 动态地创建一个Script , 将当前用户输入的内容捆绑到上述网址, 这就可以了.
再来处理第三项, 如何将服务商返回的数据返回到用户? 显然, 处理包括了两部分:解析数据, 提交给用户. 这里只讲解解析数据.
Google Suggest 返回的是一个数组, 结构如下:
[
(数组第一项元素)<用户输入的内容>,
(数组第二项元素, 也是一个数组)[
[第一条关联结果的文本, 第一条关联结果的相关记录数, 序号],
[第二条关联结果...],
[...]
],
(数组第三项元素)<空白项>
]
显然, 只处理第二个元素就可以了.
这个数组元素, 也是一个数组, 它包含了n条关联结果, 而每一条关联结果, 也是一个数组, 晕...它包含3项, 第一项是这条关联结果的文本, 也就是用来显示给用户看的, 第二项, 是这条关联结果所对应的相关记录的数量.
以"香港"二字为例, 服务商返回的关联结果有10条, 整个数组就是这样:
[ "香港",
[ ["香港旅游", "123,000条结果", 0],
["香港酒店", "9,000条结果", 1],
...
],
]
具体解析代码就不给出了, 基本上就是分析数组、提数组元素的操作.
再来说第四项: 当用户点击其中一条关联时, 它就被复制到输入框, 成为用户的输入内容, 也就是做到一触即发, 一旦点击, 立即启动, 具体内容此处也不详述了.
最后, 来处理第一部分: 如何监测用户的输入? 网上很多教程都使用监测用户击键这种方式, 我认为有几点不妥:
第一, 对中文输入的支持不好. 动手测试一下就知道了, 在一个<input type='text'>里面, 分别输入中文和英文, 所触发的JavaScript事件是不同的, 更令人头痛的是, 不同的浏览器又有各自不同的事件响应, 十分麻烦.
第二, 如果没有击键动作的话, 比如, 用户从记事本复制一段文本, 然后粘贴到搜索输入框内, 再点击搜索按钮, 整个过程都没有击键动作, 这样就不会触发搜索关联了.
第三, 每打入一个字符就触发一次关联查询, 这会造成较大的系统负担, 事实并不需要一定如此, 为何不采用更轻巧的方式呢?
我使用的方式(据说也是Google 采用的方式, 但未经证实), 是通过定时器对输入框进行检查, 即大家都应该熟悉的 setTimeout .
一般而言, 大多数人的中文输入速度大约是 60字/分钟(这里不考虑诸如词组输入之类的便捷方式, 因为关键不在于输出多少个字, 而在于键入的速度), 因此, 可以将定时器的时间间隔设为稍大一点, 这样, 在保证监测效果的前提下, 不会对系统造成较大的负担.
更进一步地, 根据实际情况进行优化: 仅当用户在输入框内输入内容时才进行监测, 换言之, 如果用户不在输入框内输入内容, 那就关闭定时器, 这就更加减少了系统负担.
怎样判断用户正在输入内容呢? 很简单, 将输入框的onfocus事件(获得焦点事件)捆绑到指定的监视过程上, 同理, 将onblur(失去焦点事件)也捆绑到指定监视过程上, 这样就可以了! 道理很简单: 用户要在输入框内输入内容, 自然首先要将输入焦点转移到输入框(例如,用鼠标在输入框内点击一下), 这样, onfocus事件被激发, 被捆绑的监视过程也就被激活了, 而这个监视过程的任务就是启动定时器, 按照一定的时间间隔对输入框进行检查, 一旦发现有输入内容则立即向服务商发出一个关联查询请求, 同理, 当用户点击页面上其他元素, 例如, 点击某一条链接, 打开一份网页, 输入焦点也就从输入框转移走了, onblur事件也就被激发了, 捆绑的监视过程也就被激活了, 执行关闭定时器的操作.
不同的服务商, 所返回的应答是不同格式的, 即使是同一服务商, 比如Google, 它也不是一成不变的, 因此, 要注意检查应答内容.
现在, Google 返回的应答是一个类方法(Class Method)调用, 换言之, 如果当前页面没有加载这个类, 那就不能正确解析它所包含的数据了, 因此, Hack 也就派上用场了.
Google返回的script 内容:
window.google.ac.h([关联内容])
很简单, 在页面内创建一个google类, 再在该类内部创建一个ac类, 并为它添加一个名为h 的类方法就可以了, 即:
MyGoogleAC = function()
{ this.h = function(Content) { ... } }
MyGoogle = function()
{ this.ac = new MyGoogleAC; }
var google = new MyGoogle;
总结一下:
1. 做好接口, 也就是实现google类实例, 这样才可以正确地接收及处理 Google Suggest返回的数据,
2. 做好监视过程, 即输入框的onfocus事件响应过程和onblur事件响应过程. 监视的目的, 就是为了及时向Google Suggest发出当前用户输入的内容.
3. 做好用户选择响应过程, 即, 一旦用户选择某一条关联时, 应及时地作出相应的处理.