Google Suggest Autcomplete 的实现

前台:

HTML

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>Using Google Search</title>

<script type="text/JavaScript" src="fun.js">

</script>

</head>

<body>

<h1>Google Suggest</h1>

<input type="text" id="tb_kw" name="textField" onkeyup="connectGoogleSuggest()" style="width: 270px"/>

 <div id="targetDiv" style="position:absolute;border:solid 1px black; z-index:20000; background-color:White; display:none;"></div>

</body>

</html>

func.js:

function $(i) { return document.getElementById(i);}

function getPosition(ele){

    var overflown = [];

    var el = ele, left = 0, top = 0;

    do {

       left += el.offsetLeft || 0;

       top += el.offsetTop || 0;

       el = el.offsetParent;

    } while (el);

    return {'x': left, 'y': top};

}

function connectGoogleSuggest() {

    var input = $("tb_kw");

    var h=$("targetDiv");

    //h._i=-1000;

    if (!input.value||!input.value.length||event.keyCode=='27')

    {

        h.style.display="none";

        return;

    }

    if (event.keyCode=='38' || event.keyCode=='40')

    {

       // alert(h.style.display);

        if (h.style.display=="none")

        {

            return;

        }

        if (event.keyCode=='38')

        {

        //alert(event.keyCode);

            if (h._i==-1)

            {

                h._i=h.firstChild.rows.length-1;

            }

            else

            {

                h._i--;

            }

        }

        else

        {

        //alert(h._i);

           h._i++;

        }

        for(var i=0; i<h.firstChild.rows.length; i++)

        {

            h.firstChild.rows[i].style.backgroundColor="#FFFFFF";

        }

        if(h._i >= 0 && h._i < h.firstChild.rows.length)

            with(h.firstChild.rows[h._i])

            {

                style.backgroundColor="#D0ECF9";

                input.value=cells[0].innerText;

            }

        else

        {

            input.value=h._kw;

            h._i=-1;

        }

    }

   else if(input.value!="") {

        h._i=-1;

        h._kw=input.value;

        getData("google.aspx?qu="+input.value);

        var pos=getPosition($("tb_kw"));

        with(h.style)

        {

          left=pos.x;

          top=pos.y+$("tb_kw").offsetHeight;

          width=$("tb_kw").offsetWidth-4;

          display="block";

        }

    }

    else {

        $("targetDiv").innerHTML= "";

    }

}

function getData(source){

    var xmlHttp = false;

    if (window.XMLHttpRequest)

        xmlHttp = new XMLHttpRequest();

    else if (window.ActiveXObject)

        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");

    if (xmlHttp){

        xmlHttp.open("GET",source);

        xmlHttp.onreadystatechange=function(){

            if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {

                var message=xmlHttp.responseText;

                var callBack = message.substring("window.google.ac.".length, message.length);

                eval(callBack);

            }

        }

        xmlHttp.send(null);

    }

}

function Suggest_apply(unusedVariable, searchWord, results,unusedArray){

    if(!results || results.length<3)

        return;

    var ihtml="";

    for(var j=1;j<results.length;j+=2)

        ihtml+='<tr style="cursor:hand" onmouseover="MouseOver(this);$(\'tb_kw\').value=\'' +results[j] +'\';" onmouseout="MouseOut(this);" onclick="ResultOnClick();"><td style="color:#000" align="left">' +results[j] +'</td><td style="color:#090" align="right">' +results[j+1] +'</td></tr>';

     $("targetDiv").innerHTML="<table width='100%' border='0' cellpadding='0' cellspacing='0' style='font-size:12px;'>"+ihtml+"</table>";

     $("targetDiv").style.display="block";

}

function MouseOver(Tr){

    Tr.bgColor="#D0ECF9";

    Tr.childNodes[0].style.color="#00cc00";

    Tr.childNodes[1].style.color="#00cc00";

}

function MouseOut(Tr){

    Tr.bgColor="";

    Tr.childNodes[0].style.color="#000000";

    Tr.childNodes[1].style.color="#009900";

}

function ResultOnClick()

{

    $("targetDiv").style.display="none";

}

后台:

google.aspx

<%@ Page Language="C#" AutoEventWireup="true" Debug="true" CodeFile="google.aspx.cs" Inherits="google" %>

记住:一定要只保留这一句话,其他的就去掉

google.aspx.cs

using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

using System.Text;

using System.IO;

using System.Net;

 

public partial class google : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

        string ret = GetPageHtml("http://www.google.cn/complete/search?hl=zh-CN&client=suggest&js=true&qu=" + Request.QueryString["qu"]);

        Response.Write(ret);

    }

    protected string GetPageHtml(string url)

    {

        string pageinfo;

        try

        {

            WebRequest myreq = WebRequest.Create(url);

            WebResponse myrep = myreq.GetResponse();

            StreamReader reader = new StreamReader(myrep.GetResponseStream(), Encoding.GetEncoding("UTF-8"));

            pageinfo = reader.ReadToEnd();

        }

        catch

        {

            pageinfo = "";

        }

        return pageinfo;

    }

}

上面把代码全部贴出来了,下面我就简单讲解一下。

我们用的是Google SuggestAPI,即这个页面

http://www.google.cn/complete/search?hl=zh-CN&client=suggest&js=true&qu=" + Request.QueryString["qu"])

这里我们将我们的搜索词作为QueryString传了过去,在google.aspx.cs页面进行分析

如下:

string ret = GetPageHtml("http://www.google.cn/complete/search?hl=zh-CN&client=suggest&js=true&qu=" + Request.QueryString["qu"]);

        Response.Write(ret);

GetPageHtml()方法源码如下:

protected string GetPageHtml(string url)

    {

        string pageinfo;

        try

        {

            WebRequest myreq = WebRequest.Create(url);

            WebResponse myrep = myreq.GetResponse();

            StreamReader reader = new StreamReader(myrep.GetResponseStream(), Encoding.GetEncoding("UTF-8"));

            pageinfo = reader.ReadToEnd();

        }

        catch

        {

            pageinfo = "";

        }

        return pageinfo;

    }

}

GetPageHtml()的主要功能就是获得请求的web页的内容。

Ret就是我们要的结果,就是我们回调函数的返回结果,返回一个数组,比如搜索词为AJAX,则有

window.google.ac.Suggest_apply(frameElement, "AJAX", new Array(2 , "ajax技术", "2,400,000 结果" , "ajax基础教程", "444,000 结果" , "ajax 框架", "860,000 结果" , "ajax教程", "1,210,000 结果" , "ajaxcontroltoolkit", "297,000 结果" , "ajaxpro", "89,200 结果" , "ajax .net", "2,060,000 结果" , "ajax中国", "2,550,000 结果" , "ajax 实例", "884,000 结果" , "ajax post", "18,700,000 结果" ), new Array(""));

所以我们得出结论:回调函数是window.google.ac.Suggest_apply(a, b, c, d), c就是我们要的结果,所以我们在回调函数中只需要使用c这个数组就得了。

另外就是AJAX的套路,xmlHttp请求,这里我们用一个函数function getData(source)实现

function getData(source){

    var xmlHttp = false;

    if (window.XMLHttpRequest)

        xmlHttp = new XMLHttpRequest();

    else if (window.ActiveXObject)

        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");

    if (xmlHttp){

        xmlHttp.open("GET",source);

        xmlHttp.onreadystatechange=function(){

            if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {

                var message=xmlHttp.responseText;

                var callBack = message.substring("window.google.ac.".length, message.length);

                eval(callBack);

            }

        }

        xmlHttp.send(null);

    }

}

为什么我们要在google.aspx.cs中进行处理呢?原因是这样的,大多数的浏览器都不支持跨域的JS访问,从而我们要从后台进行处理后再请求,就不是跨域访问了。

接下来解决的问题是我们的autocomplete的结果接收的DIV的位置了,位置可以这样实现:

function getPosition(ele){

    var overflown = [];

    var el = ele, left = 0, top = 0;

    do {

       left += el.offsetLeft || 0;

       top += el.offsetTop || 0;

       el = el.offsetParent;

    } while (el);

    return {'x': left, 'y': top};

}

参数ele代表的是文本框,所以文本框在哪里,结果接收DIV就相应的在该在的地方出现,以下为效果图:

 

接下来是实现回调函数

function Suggest_apply(unusedVariable, searchWord, results,unusedArray){

    if(!results || results.length<3)

        return;

    var ihtml="";

    for(var j=1;j<results.length;j+=2)

        ihtml+='<tr style="cursor:hand" onmouseover="MouseOver(this);$(\'tb_kw\').value=\'' +results[j] +'\';" onmouseout="MouseOut(this);" onclick="ResultOnClick();"><td style="color:#000" align="left">' +results[j] +'</td><td style="color:#090" align="right">' +results[j+1] +'</td></tr>';

     $("targetDiv").innerHTML="<table width='100%' border='0' cellpadding='0' cellspacing='0' style='font-size:12px;'>"+ihtml+"</table>";

     $("targetDiv").style.display="block";

}

$(i)是函数function $(i) { return document.getElementById(i);}

主要是为了节省codes。我们实际上是生成了一个<table></table>,里面就是我回调的结果,我们把鼠标时间一通加在了拼接的字符串里面,就是鼠标放到某一个结果上之后,字体颜色改变,背景色改变,然后该项的关键字成为搜索框里面的内容。

一下就是鼠标触发事件函数

function MouseOver(Tr){

    Tr.bgColor="#D0ECF9";

    Tr.childNodes[0].style.color="#00cc00";

    Tr.childNodes[1].style.color="#00cc00";

}

function MouseOut(Tr){

    Tr.bgColor="";

    Tr.childNodes[0].style.color="#000000";

    Tr.childNodes[1].style.color="#009900";

}

function ResultOnClick()

{

    $("targetDiv").style.display="none";

}

有鼠标移到结果上,鼠标移开,鼠标点击等。

 

接下来就是事件函数的主体及其键盘操作

function connectGoogleSuggest() {

    var input = $("tb_kw");

    var h=$("targetDiv");

    //h._i=-1000;

    if (!input.value||!input.value.length||event.keyCode=='27')

    {

        h.style.display="none";

        return;

    }

    if (event.keyCode=='38' || event.keyCode=='40')

    {

       // alert(h.style.display);

        if (h.style.display=="none")

        {

            return;

        }

        if (event.keyCode=='38')

        {

        //alert(event.keyCode);

            if (h._i==-1)

            {

                h._i=h.firstChild.rows.length-1;

            }

            else

            {

                h._i--;

            }

        }

        else

        {

        //alert(h._i);

           h._i++;

        }

        for(var i=0; i<h.firstChild.rows.length; i++)

        {

            h.firstChild.rows[i].style.backgroundColor="#FFFFFF";

        }

        if(h._i >= 0 && h._i < h.firstChild.rows.length)

            with(h.firstChild.rows[h._i])

            {

                style.backgroundColor="#D0ECF9";

                input.value=cells[0].innerText;

            }

        else

        {

            input.value=h._kw;

            h._i=-1;

        }

    }

   else if(input.value!="") {

        h._i=-1;

        h._kw=input.value;

        getData("google.aspx?qu="+input.value);

        var pos=getPosition($("tb_kw"));

        with(h.style)

        {

          left=pos.x;

          top=pos.y+$("tb_kw").offsetHeight;

          width=$("tb_kw").offsetWidth-4;

          display="block";

        }

    }

    else {

        $("targetDiv").innerHTML= "";

    }

}

记住,js很宽松,当你给一个对象随便赋值一个属性时,该属性就是该对象的属性了,比如本来objA没有pro1属性,但是当执行运算objA.pro1后,pro1就是它的属性了。基于上述观点,我们有里面的h._i出现,不然一般人还看半天还摸不着头。

主要处理了上下键的操作和控制接收结果的DIVtargetDiv”的某一些样式。然后把这个主要事件函数作为输入框的onkeyup触发事件,当每发生一次按键事件时,便执行一次。实现了实时改变结果的功能。

一个地道的Google Suggest就做好了,大家鼓掌!

                 马劲 lkmmmj@gmail.com 2008-11-30 于华中科技大学东七楼607