您的位置:首页 > Web前端 > JQuery

JQuery+ajax实现类似百度搜索自动匹配功能

2015-10-23 18:39 1301 查看
   

   引言

   我们接触最多的、用的最多的搜索引擎就是百度了,可以说现在我们的生活如果离开像百度、谷歌这样的搜索

引擎还是我们的生活没有了方向,我们在使用的时候都有一个体验就是我我们在输入关键紫的时候,他会自动给我们

匹配很多的关键字,像下图所示:

       


   这种非常人性化的功能对于我们在平常开发软件的时候是非常有必要借鉴的,所以在小编最近的项目中就需要

用到这个功能给用户提供方便,于是小编就对这个方面的内容进行了研究,必备的知识可能是JQuery+Ajax,因为这

需要频繁的刷新网页,因为我们在输入框中内容发生改变的时候,下拉框中的内容是需要改变的,下面小编就给大家

分享一下小编的实现代码和思路。

   首先给大家说一下后台的思路,既然是自动匹配所以我们用到模糊查询的功能:

   

#region  模糊查询 提供自动匹配违规公司
public ActionResult QueryIllegalCompany()

{
//获得搜索框中输入的内容
string CompanyName = Request["strLike"];
//调用后台的模糊查询方法查询匹配的数据,返回值为list
List<BlackListViewModel> IllegalCompany = iBlackListManagerWCF.QueryIllegalCompany(CompanyName);

string[] results = { "CompanyName" };
//将需要的字段拼接成字符串
string s = FuzzyQuery.GetLikeStr<BlackListViewModel>(IllegalCompany, results).ToString();

return Content(s);

}
#endregion


   下面来看一下前台页面的代码:

<pre name="code" class="html"> <tr margin-left:40px>
<td style="margin-left:40px;font-size:14px">公司名称:</td>
<td style="width:300px">
<input type="text" value="请输入公司名称" id="companyName" onblur="QueryCompanyInfo(this)" onchange="QueryIllegalCompany()" onfocus=" if (this.value == this.defaultValue) this.value = ''" class="easyui-validatebox" required="true" missingmessage="公司名称必须填写" size="10" type="text" />
</td>

</tr>
@*存放后台链接地址的隐藏input*@
<input id="urllink" type="hidden" value="/BidTRecordManager/QueryIllegalCompany" />
@*添加存放模糊查询结果的自动提示框*@
<div id="auto" style="z-index:4; position: absolute; display: none; border: 1px solid #95b8e7; background-color:#fff"></div>




   下面分享一下最为关键的js代码:

//跨浏览器现代事件绑定queryCondition
function addEvent(obj, type, fn) {
if (obj.addEventListener) {//火狐浏览器
obj.addEventListener(type, fn, false);
} else if (obj.attachEvent) {//ie浏览器
obj.attachEvent("on" + type, fn);
}
}

addEvent(window, "load", function () {

var input = document.getElementById("companyName");

addEvent(input, "keyup", function (event, input, urllink) {
var xmlHttp;
var params;
var strLike;
var input = document.getElementById("companyName");
var keycode = AutoComplete.prototype.isIE() ? window.event.keyCode : event.which;//e.which代表火狐中的键码

if (typeof XMLHttpRequest != 'undefined') {//火狐浏览器
xmlHttp = new XMLHttpRequest();

} else if (typeof ActiveXObject != 'undefined') { //IE浏览器
var version = [
'MSXML2.XMLHttp.6.0',
'MSXML2.XMLHttp.3.0',
'MSXML2.XMLHttp'
];
for (var i = 0; i < versions.length; i++) {
try {
xmlHttp = new ActiveXObject(version[i]);
} catch (e) {
//跳过
}
}
} else {
throw new Error('您的浏览器不支持XHR对象!');

}

//定义要访问的url和提交方式
strLike = document.getElementById("companyName").value;
//var url = "queryTestHandler.ashx?strLike=" + strLike + new Date().getTime();
var urllink = document.getElementById("urllink").value;

var url = urllink + "?strLike=" + strLike + "&t=" + new Date().getTime();
xmlHttp.open("get", url, true);//get方式提交
xmlHttp.setRequestHeader("Content-Type", "text/xml");//设置请求头信息
xmlHttp.send(null);

xmlHttp.onreadystatechange = callback;
function callback() {

if (xmlHttp.readyState == 4) {

//表示和服务器端的交互已经完成
if (xmlHttp.status == 200) {

//表示和服务器的响应代码是200,正确的返回了数据
//纯文本数据的接受方法
params = xmlHttp.responseText;
if ((keycode >= 37 && keycode <= 40) || keycode == 13) {
if (autoComplete != null && (keycode == 38 || keycode == 40 || keycode == 13)) {
autoComplete.setStyle(keycode);
}
}
else {

autoComplete = new AutoComplete(params, input);
autoComplete.show();
}
}
}

}//callback End

})
})

//出现两个模糊查询输入框要调用的方法
setTimeout(function AutoSuggest(input, event, urllink) {
var xmlHttp;
var params;
var strLike;
//alert();
//alert(input);
//alert(urllink);
//alert(input.value);
var keycode = AutoComplete.prototype.isIE() ? window.event.keyCode : event.which;//e.which代表火狐中的键码
//alert();
if (typeof XMLHttpRequest != 'undefined') {//火狐浏览器
xmlHttp = new XMLHttpRequest();

} else if (typeof ActiveXObject != 'undefined') { //IE浏览器
var version = [
'MSXML2.XMLHttp.6.0',
'MSXML2.XMLHttp.3.0',
'MSXML2.XMLHttp'
];
for (var i = 0; i < versions.length; i++) {
try {
xmlHttp = new ActiveXObject(version[i]);
} catch (e) {
//跳过
}
}
} else {
throw new Error('您的浏览器不支持XHR对象!');

}

//定义要访问的url和提交方式
//strLike = document.getElementById("queryCondition").value;
//var url = "queryTestHandler.ashx?strLike=" + strLike + new Date().getTime();
// var urllink = document.getElementById("urllink").value;
strLike = input.value;
//alert(strLike);
var url = urllink + "?strLike=" + strLike + "&t=" + new Date().getTime();
xmlHttp.open("get", url, true);//get方式提交
xmlHttp.setRequestHeader("Content-Type", "text/xml");//设置请求头信息
xmlHttp.send(null);

xmlHttp.onreadystatechange = callback;
function callback() {

if (xmlHttp.readyState == 4) {

//表示和服务器端的交互已经完成
if (xmlHttp.status == 200) {

//表示和服务器的响应代码是200,正确的返回了数据
//纯文本数据的接受方法
params = xmlHttp.responseText;
if ((keycode >= 37 && keycode <= 40) || keycode == 13) {
if (autoComplete != null && (keycode == 38 || keycode == 40 || keycode == 13)) {
autoComplete.setStyle(keycode);
}
}
else {

autoComplete = new AutoComplete(params, input);
autoComplete.show();
}
}
}

}//callback End
}, 100);

//AutoComplete Object
var autoComplete = null;

//AutoComplete constructor
function AutoComplete(params, input){
this.params = params//接收的参数,这里的参数为接收的所有需要查询的数据源
this.input = input;//Input输入的值
this.messages = new Array();//将所有需要查询的数据分成一个数组的形式,messages代表这个数组
this.message = input.value;//单数形式代表当前输入的值
this.inputValue = "";//原始输入值默认为空
this.size = 0;//下拉提示框条数为空,默认
this.index = 0;//当前选中的内容索引
this.likemsgs = new Array();//下拉框中要显示的数据,相似数据,作为一个数组来出现
//this.likemsgs = this.unique(this.likemsgs);
this.div = this.$$$('auto');//通过$$$代表getElementById,自动提示框的节点
this.divInnerHTML = this.div.innerHTML;//自动提示框的内容
this.input.onblur = function(){
autoComplete.lostFocus();
}
}

//keyup事件需要调用的方法,params为需要查询的所有数据源,input为输入的值,e为keyup事件

//将字符串转换成数组的方法
AutoComplete.prototype.strToArray = function(){
this.messages = this.params.split(",");
}

//展现自动提示框
AutoComplete.prototype.show = function(){
if (this.message != '') {
this.inputValue = this.input.value;
this.strToArray();
this.emptyDiv();
this.getLikeMegs();
this.setDivAttr();
this.addMessageToDiv();
}
else {
this.emptyDiv();
}
}

//Style set of information
AutoComplete.prototype.setStyle = function(keycode){
if (this.size > 0) {
if (keycode == 38) {//Up上键
this.setStyleUp();
}
else
if (keycode == 40) { //Down下键
this.setStyleDown();
}
else
if (keycode == 13) {//Enter

this.textToInput(this.$$$(this.index).innerText);

}
}
}

//按上键时,设置鼠标上移事件,及相应的格式
AutoComplete.prototype.setStyleUp = function(){
if (this.index == 0) {//如果当前选中内容索引为0,默认没有匹配项的情况
this.index = this.size;//如果索引值与下拉框中内容条数相同
this.$$$(this.index).style.backgroundColor = '#E2EAFF';//出现粉色背景
this.input.value = this.$$$(this.index).innerText;
}
else
if (this.index == 1) {
this.$$$(this.index).style.backgroundColor = '#FFFFFF';//背景为白色
this.input.value = this.inputValue;
this.index = 0;
this.input.focus();
}
else {
this.index--;
this.setOtherStyle();
this.$$$(this.index).style.backgroundColor = '#E2EAFF';
this.input.value = this.$$$(this.index).innerText;
}
}

//点击down时,触发事件,设置提示框中内容的样式
AutoComplete.prototype.setStyleDown = function(){
if (this.index == this.size) {
this.$$$(this.index).style.backgroundColor = '#FFFFFF';
this.input.value = this.inputValue;
this.index = 0;
this.input.focus();
}
else {
this.index++;//否则的话,当前索引继续加
this.setOtherStyle();
this.$$$(this.index).style.backgroundColor = '#E2EAFF';
this.input.value = this.$$$(this.index).innerText;
}
}

//设置没有被选中的内容背景色为白色
AutoComplete.prototype.setOtherStyle = function(){
for (var i = 1; i <= this.size; i++) {
if (this.index != i) {
this.$$$(i).style.backgroundColor = '#FFFFFF';
}
}
}

//当浏览器改变大小时,设置提示框的样式
window.onresize = function(){
if (autoComplete != null) {
autoComplete.setDivAttr();
}
}

//当鼠标点击浏览器的其他地方时,页面的响应事件,要求如果输入那么,文本框中的值,为当前输入的值 --  //firefox
window.onclick = function(e){
if (AutoComplete.prototype.$$$('auto').style.display != 'none') {
var x = e.clientX, y = e.clientY;
var left = autoComplete.calcOffsetLeft(autoComplete.input);
var right = autoComplete.calcOffsetLeft(autoComplete.input) + autoComplete.input.offsetWidth;
var top = autoComplete.calcOffsetTop(autoComplete.input);
var bottom = autoComplete.input.offsetHeight + autoComplete.calcOffsetTop(autoComplete.input) + autoComplete.div.offsetHeight;
if (x < left || x > right || y < top || y > bottom) {
autoComplete.emptyDiv();// 如果鼠标点击的地方为浏览器的可见区,那么清空提示框
}
}
}

//设置鼠标移入事件
AutoComplete.prototype.mouseover = function(li){
li.style.backgroundColor = '#E2EAFF';//背景色
this.index = li.id;//鼠标移入时,当前索引为菜单项中所选的内容的索引
this.setOtherStyle();
}

//设置提示框的样式,包括宽和高等基本属性
AutoComplete.prototype.setDivAttr = function(){
if (this.input != null) {
this.div.style.width = this.input.offsetWidth + 'px';//宽度和输入框的宽度相同
this.div.style.left = this.calcOffsetLeft(this.input) + 'px';//与输入框左边距离相同
this.div.style.top = (this.input.offsetHeight + this.calcOffsetTop(this.input)) + 'px';//设置高度为输入框距离顶端的距离+输入框的高度
this.div.style.display = 'block';//作为一个单独的块儿来显示
}
}

//消除重复记录
AutoComplete.prototype.unique = function (someArray) {
//alert(someArray);
tempArray = someArray.slice(0);//复制数组到临时数组
for (var i = 0; i < tempArray.length; i++) {
for (var j = i + 1; j < tempArray.length;) {
//这里需要用正则表达式替换掉所有两边的空格
if (tempArray[j].replace(/(^\s+)|(\s+$)/g, "") == tempArray[i].replace(/(^\s+)|(\s+$)/g, ""))
//后面的元素若和待比较的相同,则删除并计数;
//删除后,后面的元素会自动提前,所以指针j不移动
{
tempArray.splice(j, 1);
}
else {
j++;
}
//不同,则指针移动
}
}
return tempArray;
}

AutoComplete.prototype.getLikeMegs = function () {
var j = 0;
for (var i = 0; i < this.messages.length; i++) {
if ((this.messages[i].length >= this.message.length)) {
for (var k = 0; k < this.messages[i].length; k++) {
if (this.messages[i].substring(k, k+this.message.length) == this.message ) {
//消除重复记录
this.likemsgs[j++] = this.messages[i];
}
}
}
}
this.likemsgs = this.unique(this.likemsgs);
}
//把查询到的可能匹配的结果添加进提示框中
AutoComplete.prototype.addMessageToDiv = function(){
var complete = this;
for (var i = 0; i < this.likemsgs.length; i++) {
var li = document.createElement('li');//创建一个菜单节点
li.id = i + 1;
li.style.fontSize = '12px';
li.style.listStyleType = 'none';
li.style.listStylePosition = 'outside';//不占用Li宽度
li.onmouseover = function(){//设置鼠标上移事件
complete.mouseover(this);
}
li.onmouseout = function(){//设置鼠标移除事件
this.style.backgroundColor = '#FFFFFF';//背景为白色
}
li.onclick = function(){//鼠标点击时,文本框内容为点击内容
complete.textToInput(this.innerText);
}
li.appendChild(document.createTextNode(this.likemsgs[i]));//创建一个此内容的文本节点,并添加进li菜单项中
this.div.appendChild(li);//将菜单项添加进提示框中
this.divInnerHTML = this.div.innerHTML;
this.size++;
}
if (this.size == 0) {//如果没有匹配项,size=0为空结果
this.div.innerHTML = "<li style=\"list-style: none outside;font-size:12px;color:red;\">未找到相匹配的结果!</li>";
this.divInnerHTML = this.div.innerHTML;
}
}

//设置鼠标点击时,文本框中的内容跟点击时相同,同事清空提示框中的内容
AutoComplete.prototype.textToInput = function(value){
this.input.value = value;
this.emptyDiv();
}

//清空提示框中的内容
AutoComplete.prototype.emptyDiv = function(){
this.divInnerHTML = '';
this.div.innerHTML = this.divInnerHTML;
this.div.style.display = 'none';
this.size = 0;
this.index = 0;
}

//计算物体左边到提示框左边之间的距离
AutoComplete.prototype.calcOffsetLeft = function(field){
return this.calcOffset(field, 'offsetLeft');
}

//设置物体从顶端到当前提示框之间的距离
AutoComplete.prototype.calcOffsetTop = function(field){
return this.calcOffset(field, 'offsetTop');
}

//设置物体到浏览器左边的距离,这里主要用来计算输入框到浏览器左边的距离
AutoComplete.prototype.calcOffset = function(field, attr){
var offset = 0;
while (field) {
offset += field[attr];
field = field.offsetParent;
}
return offset;
}

//当输入框失去焦点时IE浏览器,清空提示框
AutoComplete.prototype.lostFocus = function(){
var active = document.activeElement;
if (AutoComplete.prototype.isIE() && active != null && active.id != 'auto') {
this.emptyDiv()
}
}

//Use $$$ replace getElementById
AutoComplete.prototype.$$$ = function(obj){
return document.getElementById(obj);
}

//判断当前浏览器为IE浏览器
AutoComplete.prototype.isIE = function(){
return window.navigator.userAgent.indexOf('MSIE') != -1;
}

//Firefox innerText define
if (!AutoComplete.prototype.isIE()) {
HTMLElement.prototype.__defineGetter__("innerText", function(){
var anyString = "";
var childS = this.childNodes;
for (var i = 0; i < childS.length; i++) {
if (childS[i].nodeType == 1) //元素节点
anyString += childS[i].innerText;
else
if (childS[i].nodeType == 3) //文本节点
anyString += childS[i].nodeValue;
}
return anyString;
});
HTMLElement.prototype.__defineSetter__("innerText", function(sText){
this.textContent = sText;
});
}


   在使用上面这个js的时候只需要将我们的搜索框的id替成我们自己的id就可以了,这就可以了实现百度搜索框

的功能了,这个js的来源是Jquery封装的一个插件AutoCoplete(点我下载),上面的js从布局样式、浏览器兼容等

方面对这个插件进行了扩展,是这个功能实现的非常的人性化。希望能对需要的读者给出非常大的帮助。

                  


   小结

   在开始的时候感觉这个功能是比较好实现的,但是在实现的过程中遇到了很多的坎坷,自己分析这个原因是自

己对js真的是太菜了,一点都不熟悉。另外也在感叹js的强大的,什么功能js都可以实现。但是需要我们对js有很深

的功底。其次是对Jquery封装的插件不能很好的扩展,因为不论是API文档还是别人写的js我们都需要读懂并且能很

好的修改,这样我们才能真正的叫做站在巨人的肩膀上。对目前的自己来说js还非常的嫩,几乎自己写不出js的代

码,所以我们在学习的过程中需要不断的积累这个方面的代码量,这样当我们接触到新的功能的时候才能写出非常优

秀的js代码,希望这篇博客能给广大读者带来帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: