自动补全搜索实现
时间:2022-05-04
本文章向大家介绍自动补全搜索实现,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
目前大多数搜索框都已实现自动补全功能,自己也私底下实现了一个简易版本,
在此总结过程中的一些要点:
1,侦听文本框的value值改变,注意在Ie8及其之前版本的onpropertychange和Ie9的oninput事件与
W3C下的oninput事件的异同;
2,ajax请求数据;
3,自动补全框的定位;
4,上下键导航以及鼠标导航
在此附上源码:
.auto-ul{
list-style: none;
padding: 0;
margin: 0;
}
.auto-ul li{
margin: 0;
padding:5px;
}
.auto-ul a{
text-decoration: none;
color: black;
}
.w{
background: #cecece;
cursor: default;
}
input{
border: 1px solid #c0c0c0;
}
<div class="w250 h200 bgf0 auto tc pt15">
<div>
<form>
<label for="t">username: </label>
<input type="text" id="t" autocomplete="false" class="p5 w150 lh22">
</form>
</div>
</div>
items.txt文件
<ul>
<li>
<a href="#" class="db">java</a>
</li>
<li>
<a href="#" class="db">javaWeb</a>
</li>
<li>
<a href="#" class="db">javaScript</a>
</li>
<li>
<a href="#" class="db">javaScript & CSS</a>
</li>
</ul>
function $(m){
return document.getElementById(m)
}
function createBox(){
var div = document.createElement('div'),w;
w = $('t').offsetWidth;
div.id = 'box';
div.style.cssText = 'position:absolute;width:'+(w-2)+'px;border:1px solid #cecece;display:none;';
div.innerHTML = '<ul class="auto-ul" id="autobox-ul"></ul>'
return div;
}
function showBox(d,boxLocation){
d.style.display = '';
d.style.left = boxLocation.left + 'px';
d.style.top = boxLocation.top + 'px';
}
function hideBox(d){
d.style.display = 'none';
d.getElementsByTagName('ul')[0].innerHTML = '';
}
//创建xhr
function createXHR(){
if('XMLHttpRequest' in window){
createXHR = function(){
return new XMLHttpRequest();
}
}else{
var i= 0,len, fns = [function(){return new ActiveXObject('Microsoft.XMLHTTP')},function(){return new ActiveXObject('Msxml2.XMLHTTP')},
function(){return new ActiveXObject('Msxml2.XMLHTTP.3.0')},function(){return new ActiveXObject('Msxml2.XMLHTTP.6.0')}];
for(len = fns.length;i<len;i++){
try{
fns[i]();
createXHR = fns[i];
break;
}catch (e){
}
}
}
return createXHR();
}
// ajax实现
function ajaxInit(ajaxData){
var xhr = createXHR(),get_data,isLoaded = false,
map = {
'html': 'text',
'arraybuffer': 'arraybuffer',
'blob': 'blob',
'document': 'document',
'json': 'text'
};
ajaxData.onBefore = ajaxData.onBefore || function(){};
ajaxData.onSuccess = ajaxData.onSuccess || function(){};
ajaxData.onFailure = ajaxData.onFailure || function(){};
ajaxData.onComplete = ajaxData.onComplete || function(){};
ajaxData.timeout = ajaxData.timeout || 5000;
ajaxData.type = ajaxData.type || 'post';
/**
* 'text':返回类型为字符串,这是默认值。
'arraybuffer':返回类型为ArrayBuffer。
'blob':返回类型为Blob。
'document':返回类型为Document,用于xml。
'json':返回类型为JSON object,支持JSON的浏览器(Firefox>9,chrome>30),
就会自动对返回数据调用JSON.parse() 方法。也就是说,你从xhr.response属性
(注意,不是xhr.responseText属性)得到的不是文本,而是一个JSON对象。
*/
if(xhr.responseType)
xhr.responseType = ajaxData.responseType in map ? map[ajaxData.responseType] : 'text';
ajaxData.onBefore();
xhr.open(ajaxData.type,ajaxData.url,true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && !isLoaded){
// 判断响应成功的几点:
// 1,如果是访问本地文件,请求成功但不会获得响应码
// 2,IE(通过ActiveXObject创建的xhr对象)会将204设置为1223
// 3, opera会将204设置为0
if(!xhr.status && location.protocol == 'file:'
|| xhr.status == 1223
|| xhr.status == 0 || xhr.status >= 200 && xhr.status < 300
|| xhr.status == 304){
if(ajaxData.responseType.toLowerCase() == 'json'){
get_data = 'JSON' in window ? JSON.parse(xhr.responseText) :
new Function('return ' + xhr.responseText + ";");
}else if(ajaxData.responseType.toLowerCase() == 'html'){
get_data = xhr.responseText;
}else if(xhr.responseType.toLowerCase() == 'document'){
get_data = xhr.responseXML;
}else{
get_data = xhr.response;
}
ajaxData.onSuccess(get_data);
}else{
ajaxData.onFailure();
}
ajaxData.onComplete();
xhr = null;
}
}
setTimeout(function(){
isLoaded = true;
},ajaxData.timeout);
if(ajaxData.type.toLowerCase() == 'get'){
xhr.setRequestHeader('X-Request-With','XMLHttpRequest');
xhr.send(null);
}else if(ajaxData.type.toLowerCase() == 'post' && ajaxData.data){
xhr.setRequestHeader('X-Request-With','XMLHttpRequest');
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
xhr.send(ajaxData.data);
}
return xhr;
}
function addEvent(el,type,fn){
if(window.addEventListener){
el.addEventListener(type,fn,false)
}else{
el.attachEvent('on'+type,function(){
var e = window.event;
e.preventDefault = function(){
e.returnValue = false;
};
e.stopPropagation = function(){
e.cancelBubble = true;
}
fn.call(el,e);
})
}
}
//给文本框绑定事件
function bindEvent(t,fn){
var input = t;
//对输入框绑定事件
if(input.addEventListener){
input.addEventListener('input',fn,false);
}else{
input.attachEvent('onpropertychange',function(){
var e = window.event;
if(e.propertyName == 'value'){
fn();
}
});
}
if(window.VBArray && window.addEventListener && !window.WebSocket){
input.addEventListener('keyup',function(e){
var code = e.keycode || e.charcode;
if(code==8 || code==46){
fn();
}
},false) ;
input.oncut=function(){fn()};
}
//对按键事件侦听
addEvent(input,'keydown',function(e){
var l,ol = -1,nl;
if(e.keyCode == 40 || e.keyCode == 38){
e.preventDefault();
l = $('autobox-ul').getElementsByTagName('li');
for(var i=0,len=l.length;i<len;i++){
if(l[i].className == 'w'){
ol = i; //保存当前选定的选项
}
l[i].className = '';
}
if(e.keyCode == 40 || e.charCode == 40){ //下箭头
ol++;
if(ol <= len-1){
l[ol].className = 'w';
nl = l[ol];
}else{
l[0].className = 'w';
nl = l[0];
}
}else if(e.keyCode == 38 || e.charCode ==38){ //上箭头
ol--;
if(ol >= 0){
l[ol].className = 'w';
nl = l[ol];
}else{
l[l.length-1].className = 'w';
nl = l[l.length-1];
}
}
this.value = nl.getElementsByTagName('a')[0].innerHTML;
nl.className = 'w';
}
});
addEvent($('box'),'mousemove',function(e){
var t = e.target || e.srcElement,
l = $('autobox-ul').getElementsByTagName('li');
e.preventDefault();
for(var i= 0,len=l.length;i<len;i++){
l[i].className = '';
}
if(t.tagName.toLowerCase() == 'a'){
t.parentNode.className = 'w';
input.value = t.innerHTML;
}
})
//若输入框失去焦点,则隐藏补全框
addEvent(input,'blur',function(){
hideBox($('box'))
})
}
(function(){
var t = $('t'),div,boxLocation,ul;
div = createBox();
boxLocation = {
left: t.getBoundingClientRect().left + parseInt(document.documentElement.scrollLeft || document.body.scrollLeft || 0)
- parseInt(document.documentElement.clientLeft || document.body.clientLeft || 0),
top: t.getBoundingClientRect().top + parseInt(document.documentElement.scrollTop || document.body.scrollTop || 0)
- parseInt(document.documentElement.clientTop || document.body.clientTop || 0) +
parseInt(t.offsetHeight)
};
document.body.appendChild(div);
ul = $('autobox-ul');
bindEvent(t,function(){
var value = t.value;
ajaxInit({
type: 'get',
timeout: 3000,
url: './items.txt',
responseType: 'html',
onSuccess: function(data){
var d = document.createElement('div');
d.innerHTML = data;
d = d.getElementsByTagName('ul')[0];
ul.innerHTML = d.innerHTML;
showBox(div,boxLocation)
}
})
})
})()
经测试,IE8及其之前版本有bug,主要是因为onpropertychange的原因导致无法直接给文本框赋值。待修改。
- mysql密码遗忘和登陆报错问题
- 新一轮发展趋势:城市智能化已经势不可挡
- Enterprise Library 4.1学习笔记2----数据访问程序块
- 微信小程序中用户唯一ID的获取
- Mysql备份系列(2)--mysqldump备份(全量+增量)方案操作记录
- Enterprise Library 4.1学习笔记1----配置应用程序块(c/s和b/s均适用)
- 简单账本-用完即走的微信小程序
- 新技术革命和新产业变革正进行 “互联网+大数据+人工智能+”时代正到来
- 微信小程序开发及相关设置小结
- gitlab两种连接方式:ssh和http配置介绍
- C#实现微信AES-128-CBC加密数据的解密
- UrlReferrer为空的问题?
- DeepMind发文回顾2017:AlphaGo团队已迎战下一个重大挑战
- [你必须知道的.Net]读书笔记--浅clone与深clone
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Mongodb只读副本集如何切换到读写模式
- Java常用设计模式--策略模式(Strategy Pattern)
- Mongodb只读副本集如何切换到读写模式(下)
- 手把手带你搭建redis集群
- Jvm常量池、运行时常量池、字符串常量池理解
- 【Docker】命令使用大全
- Apache如何设置Enable Keep-Alive
- 【Docker】项目实战,部署自己的APP
- 用云开发快速构建最美AI毕业照小程序
- 13-2 vi-启动和退出
- Java中四种引用类型:强引用,软引用,弱引用,虚引用
- docker-compose搭建redis集群之哨兵模式
- docker-compose搭建redis集群之主从复制
- c/c++补完计划(七): 哨兵节点
- ASP.NET Core 奇技淫巧之接口代理转发