javascrip 中 onkeyup 事件在输入法情况下不稳定的山寨解决方案【有代码】
E8前一次版本升级提供了拼音智能快速输入的控件,但客户发现了一个不太好用的地方,中文输入法进行中文输入的时候 onkeyup事件不稳定,很多时候取不到,网上一查,这个问题还是一个普遍存在的问题。
在IE中触发keydown和keyup, 不触发keypress
输入值能够获得,但不稳定。有时候会延后
在Firefox:触发keydown和keypress, 不触发keyup
输入值未能获得 [Enter]后会触发keyup, 可获得输入值
在Opera中keydown, keypress和keyup都不触发,输入值也未能获得
[Enter]后,在opera 9.24中会触发keydown和keypress
输入过程中,Space和enter会触发三者
对于一个控件需要适合在各种环境上运行的,既然存在这样的一些区别,因此实现方式应该更加巧妙一些,这个问题一直困扰了好几天,后来在网上有人推荐了google的脚本文件http://www.google.cn/ac.js 虽然脚本做了干扰处理,但还是能看出它的一些思路,由于控件还有其它功能需求,不能直接照搬这个脚本文件,于是想到了一个山寨的解决方案。(感觉还是没有google流畅,但比以前的版本好很多了)
主要思路是:
不用onkeyup事件,改为 在 onfocus 时设置 setInterval 自动处理的机制判断是否有新的输入值, onblur时通过 clearInterval(oTimer) 方法取消自动处理。
用到的技术点有几个
1、用匿名函数的方法为 setInterval 传递参数,注意对象的直接传入会有问题,先传入控件的ID,找到后再传递给匿名方法
2、如果发现有不同的输入值的时候,利用XMLHTTP获取列表
3、缓存已经获得过的列表,减少后台操作
4、用动态的div 和 select 动态展示列表
5、利用键盘事件选择对应的值
6、处理特定场景下的特定键值,防止浏览器发生不意愿的动作
主要的技术点是以上几点,写脚本是个细致活,再有什么问题再继续完善了。
脚本文件如下: 希望能给到大家参考
var xmlDroplst = new ActiveXObject("Msxml2.DOMDocument.3.0"); //客户端XML对象
var arrDroplstID;
arrDroplstID = new Array(); //缓存已经XMLHTTP获取过的ID
var arrDroplstValue;
arrDroplstValue = new Array();
var iDroplstSavedCont = 0;
var objOldValue = ""; //保存控件原来的值
var xmlhttpDroplst = null;
var currTextBoxID = "-1";
var currDivID = "-1";
var currOpendDivName = "";
var oTimer;
// 设置自动检查输入并获取列表
function SetInputCheckValid(id,idSelect,idText,idFields,obj)
{
var args=[];
var object = document.getElementById(id);
var objSelect = document.getElementById(idSelect);
var objText = document.getElementById(idText);
args.push(id);
args.push(object);
args.push(objSelect);
args.push(objText);
args.push(idFields);
args.push(objText);
oTimer = setInterval(function(){
AutoGetItems.apply(this,args);
},400);
}
function SetInputCheckDisable(){clearInterval(oTimer);}
function AutoGetItems(id,object,objSelect,objText,idFields,obj)
{
var i = 0;
var j=0;
var sCurr = '';
var soptText='';
var blnAdd = false;
var xmlDroplst = new ActiveXObject("Msxml2.DOMDocument.3.0"); //客户端XML对象
if(objText != null){sCurr = objText.value;}
//为空,清除 退出
if(sCurr == "")
{
//清除现有内容
if(objSelect != null)
objSelect.options.length = 0; //清除内容
return;
}
//值相同则退出
if(sCurr == objOldValue)
return;
objOldValue = sCurr;
var sXml = getXmlHttpFields(idFields + "_" + escape(sCurr));
if(sXml != "-1")
{
//从缓存中获取到
if(object != null)
{
if(sXml=="") //没有
{
xmlDroplst.loadXML("<Root></Root>");
}
else
{
xmlDroplst.loadXML(sXml);
}
var nodes = xmlDroplst.documentElement.childNodes;
if(objSelect != null)
{
objSelect.options.length = 0; //清除内容
for (i=0;i<nodes.length;i++)
{
soptText = nodes(i).getAttribute("Text");
//动态获取的情况,所以的内容是从后台筛选过的
objSelect.add(document.createElement("OPTION"));
objSelect.options[j].text= soptText;
objSelect.options[j].value=j;
j++;
}
}
if(j >0)
{
//存在时显示
object.style.left = absoluteLocation(obj, 'offsetLeft') - 2 + "px";
object.style.top = absoluteLocation(obj, 'offsetTop') + obj.offsetHeight + 2 + "px";
object.style.width = obj.offsetWidth + 2 + 'px';
hideMe(id,'');
currOpendDivName = id;
}
}
}
else
{
if( sCurr != "")
{
//异步获取
if(xmlhttpDroplst == null)
xmlhttpDroplst = CreateDroplstXmlHttpObject();
if(xmlhttpDroplst != null)
{
try
{
xmlhttpDroplst.open("GET", "../Common/frmXmlHttpDroplst.aspx?id=" + idFields + "&curr=" + escape(sCurr), true);
//window.open("../Common/frmXmlHttpDroplst.aspx?id=" + idFields);
xmlhttpDroplst.setRequestHeader( "CONTENT-TYPE ", "application/x-www-form-urlencoded ");
xmlhttpDroplst.onreadystatechange = function()
{
if ( xmlhttpDroplst.readyState==4 )
{
sXml = xmlhttpDroplst.responseText;
if(sXml=="") //没有
{
xmlDroplst.loadXML("<Root></Root>");
}
else
{
xmlDroplst.loadXML(sXml);
}
//缓存这次结果
arrDroplstID[iDroplstSavedCont] = idFields + "_" + escape(sCurr);
arrDroplstValue[iDroplstSavedCont] = sXml;
iDroplstSavedCont++;
if(object != null)
{
var nodes = xmlDroplst.documentElement.childNodes;
if(objSelect != null)
{
objSelect.options.length = 0; //清除内容
for (i=0;i<nodes.length;i++)
{
soptText = nodes(i).getAttribute("Text");
//动态获取的情况,所以的内容是从后台筛选过的
objSelect.add(document.createElement("OPTION"));
objSelect.options[j].text= soptText;
objSelect.options[j].value=j;
j++;
}
}
if(j >0)
{
//存在时显示
object.style.left = absoluteLocation(obj, 'offsetLeft') - 2 + "px";
object.style.top = absoluteLocation(obj, 'offsetTop') + obj.offsetHeight + 2 + "px";
object.style.width = obj.offsetWidth + 2 + 'px';
hideMe(id,'');
}
}
}
}
xmlhttpDroplst.send(null);
}
catch(e3)
{
}
}
}
}
}
setInterval("AutoCloseDiv()",3000);
function setInputID(idText){currTextBoxID = idText; }
function setInputIDNone(){currTextBoxID = "-1"; }
function AutoCloseDiv()
{
if(currTextBoxID == "-1" && currDivID == "-1")
{
try{hideMe(currOpendDivName,"none");}catch(e3){}
}
}
function CreateDroplstXmlHttpObject()
{
try
{
xmlhttpDroplst = new ActiveXObject("MSXML2.XMLHTTP");
}
catch(e)
{
try
{
xmlhttpDroplst = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e2){}
}
return xmlhttpDroplst;
}
function focusToDropDown(idSelect)
{
if(event.keyCode == 40)
{
var objSelect = document.getElementById(idSelect);
if(objSelect != null)
{ try
{
//有控件不可见的情况
objSelect.focus();
if(objSelect.lenght > 0)
objSelect.options[0].selected = true;
}
catch(e1)
{
}
}
}
}
function MoverToDropDownLayer(idSelect)
{
var objSelect = document.getElementById(idSelect);
if(objSelect != null)
{
try
{
//有控件不可见的情况
objSelect.focus();
if(objSelect.selectedIndex == -1)
objSelect.selectedIndex = 0;
currDivID = idSelect;
}
catch(e1)
{
}
}
}
function absoluteLocation(element, offset)
{ var c = 0; while (element) { c += element[offset]; element = element.offsetParent; } return c;
}
function getSelectedLabel(id,idText,obj)
{
var opt = obj.options[obj.selectedIndex];
hideMe(id,'none');
var objText = document.getElementById(idText);
if(objText != null)
{
objText.value = getIdiomDeal(opt.text);
}
}
function getIdiomDeal(s)
{
var sRet = s;
if(typeof(getUserIdiomDeal) !="undefined")
{
sRet = getUserIdiomDeal(s);
}
return sRet;
}
function selectOnReturn(id,idText,obj)
{
if(event.keyCode == 8)
event.keyCode = null;
if(event.keyCode==13)
{
event.returnValue = false;
getSelectedLabel(id,idText,obj);
}
}
function hideMe(id,status)
{
var object = document.getElementById(id);
if(object != null)
{
object.style.display = status;
if(status == "none")
{
currDivID = "-1";
currTextBoxID = "-1";
}
}
}
function getItemsForDropdown(id,idSelect,idText,idFields,obj)
{
var object = document.getElementById(id);
var objSelect = document.getElementById(idSelect);
var objText = document.getElementById(idText);
var objFields = document.getElementById(idFields);
var i = 0;
var j=0;
var sCurr = '';
var soptText='';
var blnAdd = false;
if(objFields != null)
{ var sXml = objFields.value;
xmlDroplst.loadXML(sXml);
}
if(objText != null){ sCurr = objText.value; }
if(object != null)
{
var nodes = xmlDroplst.documentElement.childNodes;
if(objSelect != null)
{
objSelect.options.length = 0; //清除内容
for (i=0;i<nodes.length;i++)
{
soptText = nodes(i).getAttribute("Text");
blnAdd = false;
if(sCurr == '')
{
blnAdd = true;
}
else
{
if(soptText.toUpperCase().indexOf(sCurr.toUpperCase()) == 0)
{
blnAdd=true;
}
}
if(blnAdd == true)
{
objSelect.add(document.createElement("OPTION"));
objSelect.options[j].text= soptText;
objSelect.options[j].value=j;
j++;
}
}
}
object.style.left = absoluteLocation(obj, 'offsetLeft') - 2 + "px";
object.style.top = absoluteLocation(obj, 'offsetTop') + obj.offsetHeight + 2 + "px";
object.style.width = obj.offsetWidth + 2 + 'px';
hideMe(id,'');
currOpendDivName = id;
}
}
//来源于XMLHTTP异步获取,***未改***
function getItemsForDropdownXmlHttp(id,idSelect,idText,idFields,obj)
{
var object = document.getElementById(id);
var objSelect = document.getElementById(idSelect);
var objText = document.getElementById(idText);
var i = 0;
var j=0;
var sCurr = '';
var soptText='';
var blnAdd = false;
var xmlDroplst = new ActiveXObject("Msxml2.DOMDocument.3.0"); //客户端XML对象
if(objText != null){sCurr = objText.value;}
var sXml = getXmlHttpFields(idFields);
if(sXml != "-1")
{
//从缓存中获取到
if(object != null)
{
if(sXml=="") //没有
{
xmlDroplst.loadXML("<Root></Root>");
}
else
{
xmlDroplst.loadXML(sXml);
}
var nodes = xmlDroplst.documentElement.childNodes;
if(objSelect != null)
{
objSelect.options.length = 0; //清除内容
for (i=0;i<nodes.length;i++)
{
soptText = nodes(i).getAttribute("Text");
blnAdd = false;
if(sCurr == '')
{
blnAdd = true;
}
else
{
if(soptText.toUpperCase().indexOf(sCurr.toUpperCase()) == 0)
{
blnAdd=true;
}
}
if(blnAdd == true)
{
objSelect.add(document.createElement("OPTION"));
objSelect.options[j].text= soptText;
objSelect.options[j].value=j;
//objSelect.options[j].className = "combo-item";
j++;
}
}
}
if(j >0)
{
//存在时显示
object.style.left = absoluteLocation(obj, 'offsetLeft') - 2 + "px";
object.style.top = absoluteLocation(obj, 'offsetTop') + obj.offsetHeight + 2 + "px";
object.style.width = obj.offsetWidth + 2 + 'px';
hideMe(id,'');
currOpendDivName = id;
}
}
}
else
{
//异步获取
if(xmlhttpDroplst == null)
xmlhttpDroplst = CreateDroplstXmlHttpObject();
if(xmlhttpDroplst != null)
{
try
{
xmlhttpDroplst.open("GET", "../Common/frmXmlHttpDroplst.aspx?id=" + idFields, true);
//window.open("../Common/frmXmlHttpDroplst.aspx?id=" + idFields);
xmlhttpDroplst.setRequestHeader( "CONTENT-TYPE ", "application/x-www-form-urlencoded ");
xmlhttpDroplst.onreadystatechange = function()
{
if ( xmlhttpDroplst.readyState==4 )
{
sXml = xmlhttpDroplst.responseText;
if(sXml=="") //没有
{
xmlDroplst.loadXML("<Root></Root>");
}
else
{
xmlDroplst.loadXML(sXml);
}
//缓存这次结果
arrDroplstID[iDroplstSavedCont] = idFields;
arrDroplstValue[iDroplstSavedCont] = sXml;
iDroplstSavedCont++;
if(object != null)
{
var nodes = xmlDroplst.documentElement.childNodes;
if(objSelect != null)
{
objSelect.options.length = 0; //清除内容
for (i=0;i<nodes.length;i++)
{
soptText = nodes(i).getAttribute("Text");
blnAdd = false;
if(sCurr == '')
{
blnAdd = true;
}
else
{
if(soptText.toUpperCase().indexOf(sCurr.toUpperCase()) == 0)
{
blnAdd=true;
}
}
if(blnAdd == true)
{
objSelect.add(document.createElement("OPTION"));
objSelect.options[j].text= soptText;
objSelect.options[j].value=j;
j++;
}
}
}
if(j >0)
{
//存在时显示
object.style.left = absoluteLocation(obj, 'offsetLeft') - 2 + "px";
object.style.top = absoluteLocation(obj, 'offsetTop') + obj.offsetHeight + 2 + "px";
object.style.width = obj.offsetWidth + 2 + 'px';
hideMe(id,'');
}
}
}
}
xmlhttpDroplst.send(null);
}
catch(e3)
{
}
}
}
}
//通过缓存数组获取可以选择的值
function getXmlHttpFields(idFields)
{
var respText = "-1";
var i = 0;
for(i=0;i<iDroplstSavedCont;i++)
{
if(idFields == arrDroplstID[i])
{
respText = arrDroplstValue[i];
}
}
return respText;
}
整个控件脚本只是一部分,还有相应的aspx 后台代码 ascx代码等,这个就不一一介绍了,E8的客户可以联系我们对这个控件进行升级,或者在提供的全部源码基础上自己完善也可以,呵呵。
希望对大家有所帮助
E8在线管理平台: http://www.onlinee8.net