65.9K
CodeProject 正在变化。 阅读更多。
Home

AJAX 查找缓存

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (4投票s)

2009年2月22日

CPOL

2分钟阅读

viewsIcon

22065

downloadIcon

191

缓存服务器响应以减少服务器负载。

引言

这是一个 AJAX 控制,它使用 JQuery 启用自动完成列表的多个实例。

该项目使用了 Ajax.NET 框架。

背景

在阅读了 firefalcon 的文章(实现基于 Ajax.NET 的查找服务器控件)后,我想添加多个实例,并缓存服务器发送的信息。

使用代码

首先,我们需要实现从客户端调用的函数

using System;
using System.Collections;
using System.Web;
using Ajax;

namespace AjaxExample
{
    public partial class Index : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //Set search to call the simple example
            this.search.Attributes.Add("onkeyup", 
              "Index.GetSearchItems(this.value, GetSearchItems_CallBack);");
            Utility.RegisterTypeForAjax(typeof(Index));

            //Add autocomplete off using javascript to keep valid XHTML 1.1
            Page.ClientScript.RegisterStartupScript(typeof(System.Web.UI.Page), 
              "SeachAutocomplete", "<script type=\"text/" + 
              "javaScript\">$('#search').attr('autocomplete', 'off')</script>");
        }

        [AjaxMethod()]
        public ArrayList GetSearchItems(string query)
        {
            // use real method to query data from database instead

            ArrayList items = GetRecords();

            ArrayList matchItems = new ArrayList();

            if (query != string.Empty)
            {
                foreach (string item in items)
                {
                    if (item.ToLower().StartsWith(query.ToLower()))
                        matchItems.Add(item);
                }
            }
            return matchItems;
        }

        [AjaxMethod()]
        public ArrayList GetRecords()
        {
            ArrayList items = new ArrayList();
            items.Add("Ted");
            items.Add("Teddy");
            items.Add("Mark");
            items.Add("Alfred");
            return items;
        }
    }
}

现在,我们开始有趣的部分。我们创建一个自定义 ASPX 控制,它将自动调用服务器函数

public class AjaxLookupOnce : TextBox
{
    private string callBackFunction = "";
    private string backgroundColor = "#EEE";
    private string highlightColor = "#CCC";
    private string font = "Verdana";
    private string divPadding = "2px";
    private string divBorder = "1px solid #CCC";

    public string CallBackFunction
    {
        get { return callBackFunction; }
        set
        {
            callBackFunction = value;

            //Set the onkeyup attribute to call the function.
            this.Attributes.Add("onkeyup", 
                      "CheckAndShowArray(this);");
        }
    }

    public string BackgroundColor
    {
        get { return backgroundColor; }
        set { backgroundColor = value; }
    }

    public string HighlightColor
    {
        get { return highlightColor; }
        set { highlightColor = value; }
    }

    public string DivFont
    {
        get { return font; }
        set { font = value; }
    }

    public string DivPadding
    {
        get { return divPadding; }
        set { divPadding = value; }
    }

    public string DivBorder
    {
        get { return divBorder; }
        set { divBorder = value; }
    }
}

请注意,当设置了 CallBackFuntion 时,文本框将具有一个 onkeyup 属性,其中包含按下键时要执行的操作。

要初始化用于自动完成 div 的文本框,我们需要添加以下 JavaScript(jquery.js 对于以下操作是必需的)

var current;
var cache = new Array();

//Create result div for the textbox and cache it in the array cache
function InitializeTextboxEvent(TextboxName, StyleArray)
{
    //add "autocomplete=off" and blur attributes to the textbox
    $('#' + TextboxName).blur(hideDiv).attr('autocomplete', 'off');

    //Cache the textbox id, result div id, 
    //result div style array and result array
    var index = cache.length;
    cache[index] = new Array(4);
    cache[index]['Textbox'] = '#' + TextboxName;
    cache[index]['ResultDiv'] = createDiv(TextboxName, StyleArray);
    cache[index]['StyleArray'] = StyleArray;
    cache[index]['ResultArray'] = null;

    current = cache[cache.length];
}

//Create result div
function createDiv(TextboxID, StyleArray)
{

    divID = TextboxID + '_result';
    if ($('#' + divID).length == 0) {
        $('body').append($('<div></div>').attr('id', divID));

        $('#' + divID).css({

            'background': StyleArray['DIV_BG_COLOR'],
            'font-family' : StyleArray['DIV_FONT'],
            'padding' : StyleArray['DIV_PADDING'],
            'border': StyleArray['DIV_BORDER'],
            'width': $('#' + TextboxID).width(),
            'font-size' : '90%',
            'padding' : '2px 2px 2px 2px',
            'position' : 'absolute',
            'left': $('#' + TextboxID).offset().left + 'px',
            'top': ($('#' + TextboxID).offset().top + $('#' + 
            TextboxID)[0].offsetHeight) + 'px',
            'visibility' : 'hidden',
            'z-index' : 10000

        });
    
    }
    return '#' + divID;
}

要调用 InitializeTextboxEvent(),我们需要从之前创建的自定义控制中执行此操作。因此,我们向该类添加

protected override void Render(HtmlTextWriter writer)
{
    if (callBackFunction != string.Empty)
    {
        base.Render(writer);

        //Set the drop down box style and Initialize the textbox
        string initialize = string.Format("<script type=\"text/javaScript\">" + 
                Environment.NewLine +
                "var Style = new Array(5);" + Environment.NewLine +
                "Style['DIV_BG_COLOR']  = '{0}';" + Environment.NewLine +
                "Style['DIV_HIGHLIGHT_COLOR'] = '{1}';" + Environment.NewLine +
                "Style['DIV_FONT'] = '{2}';" + Environment.NewLine +
                "Style['DIV_PADDING'] = '{3}';" + Environment.NewLine +
                "Style['DIV_BORDER'] = '{4}';" + Environment.NewLine +
                "InitializeTextboxEvent('{5}', Style);" + Environment.NewLine +
                callBackFunction + "(CacheArray);" + Environment.NewLine +
                "</script>", BackgroundColor, HighlightColor, 
                DivFont, DivPadding, DivBorder, this.ClientID);

        Page.ClientScript.RegisterStartupScript(typeof(Page), "Register_" + 
                                                this.ClientID, initialize);
    }
}

在此函数中,我们添加了自定义控制中声明的样式元素,并使用控件的 ID 和样式数组调用了 InitializeTextboxEvent 函数。

我们还使用 CacheArray 函数缓存回调函数,如下所示

function CacheArray(response)
{
    //Calls seperate function as 'this' variables are undefined in this function
    SetCurrentArray(response.value);
}
function SetCurrentArray(response)
{
    cache[cache.length - 1]['ResultArray'] = response;
}

还记得之前在定义 CallBackFunction 时指定的 onkeyup 函数吗?现在,是时候创建它了。

//Check Value with cached results
function CheckAndShowArray(e)
{
    queryElement = e;
    if (!getCurrent())
        return false;
    var value = e.value;
    $(current['ResultDiv']).html('');
    if (trim(value).length > 0)
    {
        for (var i = 0; i < current['ResultArray'].length; i++)
        {
          if (trim(current['ResultArray'][i].toLowerCase()).startsWith(value.toLowerCase()))
              $(current['ResultDiv']).append($('<span></span>').attr('class', 
                 'results').html(current['ResultArray'][i])).append($('<br />'));
        }
    }
    addEvents($(current['ResultDiv']).html().length > 0);
}

//Return cache for the textbox queryElement
function getCurrent()
{
    var found = false;
    for (var i = 0; i < cache.length && !found; i++)
    {
        if ($(cache[i]['Textbox'])[0] == queryElement)
        {
            current = cache[i];
            found = true;
        }
    }
    return found;
}

//Hide/Show result div
function SetDivVisibility(show)
{
    if (getCurrent())
    {
        if (show)
            $(current['ResultDiv']).css({ 'visibility': 'visible' });
        else
            $(current['ResultDiv']).css({ 'visibility': 'hidden' });
    }
}
function hideDiv()
{
    SetDivVisibility(false);
}

//Add hover and click events to the results
function addEvents(show)
{
    $('.results').css({
        'font-weight': 'bold',
        'cursor': 'pointer',
        'padding': '2px'
    }).hover(
    function() {
        $(this).css({ 'background': current['StyleArray']['DIV_HIGHLIGHT_COLOR'] });
        $(current['Textbox']).unbind('blur');
    },
    function() {
        $(this).css({ 'background': current['StyleArray']['DIV_BG_COLOR'] });
        $(current['Textbox']).blur(hideDiv);
    }).click(
    function() {
        $(current['Textbox']).attr('value', $(this).text());
        hideDiv();
    });

    SetDivVisibility(show);
}

//Trim and starts with
function trim(str, chars) {
    return ltrim(rtrim(str, chars), chars);
}
function ltrim(str, chars) {
    chars = chars || "\\s";
    return str.replace(new RegExp("^[" + chars + "]+", "g"), "");
}
function rtrim(str, chars) {
    chars = chars || "\\s";
    return str.replace(new RegExp("[" + chars + "]+$", "g"), "");
}
String.prototype.startsWith = function(str) {
    return (this.match("^" + str) == str)
}

该代码只是检查缓存中所有以文本框值为开头的单词。要使用自定义表单,请使用

<Custom:AjaxLookupOnce
        runat="server" 
        id="AjaxLookupOnce2" 
        BackgroundColor="#EEE" 
        DivBorder="1px solid #CCC" 
        DivPadding="2px"  
        DivFont="Arial" 
        HighlightColor="green" 
        CallBackFunction="Index.GetRecords" />

现在,让我们看看对此的服务器响应

lightServer.jpg

如您所见,键入了两个键,但在页面加载时只有一个响应从服务器返回。

现在,让我们将其与 firefalcon 的文章(启用多个实例,使用 JQuery 和 onkeyup 而不是 onkeypress)的修改版本进行比较。此方法每次键入键时都会调用服务器。

heavyServer.jpg

再次键入了两个键,但这次它有两个服务器响应,每个响应需要 1 秒,因此下拉菜单中至少有 1 秒的延迟。

两种版本和另一个简单的示例都包含在附带的 zip 文件中。

致谢

感谢 firefalcon 提供的原始版本,我对其进行了修改。

© . All rights reserved.