写在前面
在使用keyup事件时,存在一个问题,假如想要做出类似于表单验证的demo:表单输入账号 “xxx” 后 再去ajax异步去后台数据库匹配,但是keyup事件的原理是每次键盘事件弹起就会检测,也就是输入“x”的时候就会检测,所以输入“xxx”就会使用三次ajax,这样的用户体验是不好的。再举一个例子,再用百度的时候,打开www.baidu.com 输入任意一个字符,就会自动弹出关于该字符的搜索信息,我感觉这个用户体验不好,我在输入一个字符的时候,百度搜索框下面某个新闻我很感兴趣,但是页面已经跳转,我history(-1)时,发现新闻页已经刷新了。这样我就看不到我想要看的新闻了。所以在输入“xxx”完整的字符再触发keyup事件显得比较重要。
如何实现
这个问题就是keyup事件延迟的问题。如何实现,很简单,就是使用定时器setTimeout和event.timeStamp。假设定期器为1000ms,定时器负责1000ms后触发keyup事件,setTimeout的原理就是,把当前事件的执行结果放入事件循环中,待JS引擎空闲时再去处理执行结果。event.timeStamp是一个事件的时间戳,表示发生事件的时间和日期(从 epoch 开始的毫秒数)epoch 是一个事件参考点。在这里,它是客户机启动的时间。
在keyup事件中引用event.timeStamp,last = event.timeStamp
在定时器中进行判断 if(last==event.timeStamp) 为真 则执行ajax
原理就是,last代表最后一次keyup的时间戳,你停止输入1000ms内没有再次触发keyup事件,则执行ajax,用代码表示就是(last==event.timeStamp)为真,如果你1000ms又触发了keyup事件,则继续判断,如果你停止输入1000ms内没有再次触发keyup事件,则执行ajax。
用代码完成
js:
// <input type="text" id="input"> $(function(){ $("#input").focus(); $("#input").on("keyup",function(e){ $this = $(this); last = e.timeStamp; setTimeout(function(){ // console.log(e.timeStamp); var $data_data = $this.val(); if(last-e.timeStamp===0){ $.ajax({ type:"get", url:"ajaxkeyup.php", data:{ $data:$data_data }, success:function(data){ console.log("ajax发送并接收响应成功显示的ok"); console.log(data); }, onerror:function(){ console.log("not ok"); } }) } },1000) }) })
php:
<?php $data = '123'; $getData = $_GET['$data']; if ($getData==$data) { echo "后台检测匹配失败显示的ok"; }else{ echo "后台检测匹配失败显示的failed"; } ?>
模拟数据库的数据为“123”,完整输入“123”后 执行ajax
demo如下
有点不清晰,但是效果就是当输入"123"时 触发keyup事件,执行ajax,显示ajax发送并接收成功,后台服务器也返回成功
当输入“1234”时,ajax发送并接收成功,但是后台检测失败
总结
这个问题是面试商汤科技呗问的问题,上一个被问的问题是promise实现红绿灯,这个问题是keyup事件的延迟。都使用了异步的操作方式,蚂蚁金服面试的时候也问JS有哪些异步操作,看来异步操作是JS的核心之一。
定时器setTimeout与异步ajax同时执行,既有页面无刷新的魅力也有事件循环的感觉。爽。