zoukankan      html  css  js  c++  java
  • [转]Asp.Net MVC 扩展联想控件

    本文转自:http://www.cnblogs.com/bright-lin/archive/2013/02/06/MVC_SuggestBox.html

    在web中,为改善用户体验,我们常会将一些文本输入框做成智能联想,以让用户更快更准确的输入内容。大概是这样的:当用户开始在文本框输入时,客户端脚本ajax向服务端发起请求,服务端从数据库读取返回数据,客户端解析数据附加在文本框的下拉div中供用户选择参考。

    在MVC中我们可以通过扩展HtmlHelper来封装自己写的控件,以便在整个项目中像使用 Html.TextBox("") 一样来使用自定义控件。

    扩展代码如下

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web.Mvc;
    using System.Web.Mvc.Html;
    namespace HtmlHelperExt
    {
        public static class SuggestBoxExtensions
        {
            #region SuggestBox 联想控件
    
            /// <summary>
            /// 联想控件
            /// </summary>
            /// <param name="htmlHelper"></param>
            /// <param name="name">name(id)</param>
            /// <param name="value">value</param>
            /// <param name="controller">controller</param>
            /// <param name="action">action</param>
            /// <param name="action">fieldName 要在下拉框显示的DataTable中的字段名</param>
            /// <param name="action">callBack 当选择值后的回调脚本函数</param>
            /// <param name="htmlAttributes"></param>
            /// <returns></returns>
            public static string SuggestBox(this HtmlHelper htmlHelper, string name, object value, string controller, string action,string fieldName,string callBack,IDictionary<string, object> htmlAttributes)
            {
    
                return htmlHelper.SuggestBox(name, value, controller, action,"", fieldName, fieldName, "", "", "",callBack, htmlAttributes);
            }
    
            /// <summary>
            /// 联想控件
            /// </summary>
            /// <param name="htmlHelper"></param>
            /// <param name="name">name(id)</param>
            /// <param name="value">value</param>
            /// <param name="controller">controller</param>
            /// <param name="action">action</param>
            /// <param name="headerText">下拉选框的头部文字(要显示多列用 ';'隔开)</param>
            /// <param name="displayFields">要在下拉框显示的DataTable中的字段名(要显示多列用 ';'隔开)</param>
            /// <param name="valueField">要赋文本框的字段(只能是一个,且包含在displayFields中)</param>
            /// <param name="action">callBack 当选择值后的回调脚本函数</param>
            /// <param name="htmlAttributes"></param>
            /// <returns></returns>
            public static string SuggestBox(this HtmlHelper htmlHelper, string name, object value, string controller, string action, string headerText, string displayFields, string valueField, string callBack, IDictionary<string, object> htmlAttributes)
            {
    
                return htmlHelper.SuggestBox(name, value, controller, action, headerText, displayFields, valueField, "", "", "",callBack, htmlAttributes);
            }
            /// <summary>
            /// 联想控件
            /// </summary>
            /// <param name="htmlHelper"></param>
            /// <param name="name">name(id)</param>
            /// <param name="value">value</param>
            /// <param name="controller">controller</param>
            /// <param name="action">action</param>
            /// <param name="headerText">下拉选框的头部文字(要显示多列用 ';'隔开)</param>
            /// <param name="displayFields">要在下拉框显示的DataTable中的字段名(要显示多列用 ';'隔开)</param>
            /// <param name="valueField">要赋文本框的字段(只能是一个,且包含在displayFields中)</param>
            /// <param name="keyField">选择行的主键</param>
            /// <param name="keyTextBoxName">将主键值保存在以此命名的隐藏的文本控件中,可供其他地方使用</param>
            /// <param name="keyTextBoxValue">初始化时主键文本控件中的值</param>
            /// <param name="htmlAttributes"></param>
            /// <returns></returns>
            public static string SuggestBox(this HtmlHelper htmlHelper, string name, object value, string controller, string action, string headerText, string displayFields, string valueField, string keyField, string keyTextBoxName, string keyTextBoxValue,string callBack,IDictionary<string, object> htmlAttributes)
            {
                var sb = new StringBuilder();
    
                if (htmlAttributes == null)
                    htmlAttributes = new Dictionary<string, object>();
    
                string styleStr = "";
                if (htmlAttributes.ContainsKey("style"))
                    styleStr = htmlAttributes["style"].ToString();
                string boxId = name.ToUpper() + "_SUGBOX";
                if (styleStr.Length > 0)
                    sb.Append(htmlHelper.TextBox(name, value, new { style = styleStr, autocomplete = "off" }));
                else
                    sb.Append(htmlHelper.TextBox(name, value, new { autocomplete = "off" }));
    
                sb.Append("<script type="text/javascript">");
    
                sb.AppendFormat("$('{0}').suggest({{boxId:'{1}',controller:'{2}',action:'{3}',headerText:'{4}',displayFields:'{5}',valueField:'{6}',keyField:'{7}',keyTextBoxName:'{8}',callBack:'{9}'}})",
    
                                            "#" + name, boxId, controller, action, headerText, displayFields, valueField, keyField, keyTextBoxName,callBack);
    
                sb.Append("</script>");
                if (keyTextBoxName != "")
                {
                    sb.Append(htmlHelper.Hidden(keyTextBoxName, keyTextBoxValue));
                }
                return sb.ToString();
            }
            #endregion
        }
    }
    复制代码

    通过Controller读取、解析、返回数据。将从数据库(或XML)读取的数据存入DataTable,然后转换为Json字符串再返回给客户端。本Demo中模拟数据在XML文件中。

    Controller代码如下:

    复制代码
     public class SuggestBoxController : Controller
        {
            public ActionResult Demo()
            {
                return View();
            }
            public string Suggest()
            {
                string searchText = "";
                if (Request["param"] == null)
                {
                    return "";
                }
                searchText = Request["param"].ToString();
                DataSet ds = new DataSet();
                ds.ReadXml(Server.MapPath("~/KeyWords.xml"));
                DataRow[] drs = ds.Tables[0].Select("name like '%" + searchText + "%'");
                DataTable dt = new DataTable();
                dt.Columns.AddRange(new DataColumn[] { new DataColumn("id"), new DataColumn("name") });
                int len = drs.Length;
               
                for (int i = 0; i < len; i++)
                {
                    DataRow dr = dt.NewRow();
                    dr[0] = drs[i][0];
                    dr[1] = drs[i][1];
                    dt.Rows.Add(dr);                
                }
               
                
                return CreateJsonStr(dt);
            }
    
            #region CreateJsonStr
            /// <summary>
            /// 将DataTable数据转换为Json字符串
            /// </summary>
            /// <param name="dt"></param>
            /// <returns></returns>
            public  string CreateJsonStr(DataTable dt)
            {
    
                StringBuilder JsonString = new StringBuilder();
                JsonString.Append("{ ");
                JsonString.Append(""Data":[ ");
                if (dt != null && dt.Rows.Count > 0)
                {
    
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        JsonString.Append("{ ");
                        for (int j = 0; j < dt.Columns.Count; j++)
                        {
                            if (j < dt.Columns.Count - 1)
                            {
                                JsonString.Append(""" + dt.Columns[j].ColumnName.ToString() + "":" + """ + dt.Rows[i][j].ToString() + "",");
                            }
                            else if (j == dt.Columns.Count - 1)
                            {
                                JsonString.Append(""" + dt.Columns[j].ColumnName.ToString() + "":" + """ + dt.Rows[i][j].ToString() + """);
                            }
                        }
    
                        if (i == dt.Rows.Count - 1)
                        {
                            JsonString.Append("} ");
                        }
                        else
                        {
                            JsonString.Append("}, ");
                        }
                    }
    
                }
                JsonString.Append("]}");
                return JsonString.ToString();
            }
            #endregion
        }
    复制代码

    主要核心还是在客户端的脚本中,脚本通过ajax访问服务端,并加载绑定返回数据,响应反馈用户的操作。

    View Code
    (function($) {
        var itemIndex = 0;
        $.fn.suggest = function(options) {
            var params = {
                boxId: "suggestBox",
                boxWidth: 250,
                boxHeight: 200,
                controller: "",
                action: "",
                headerText: "",
                displayFields: "",
                valueField: "",
                keyField: "",
                keyTextBoxName: "",
                callBack: ""
            };
            var ops = $.extend(params, options);
            var headerTextArr = new Array();
            var displayFieldsArr = new Array();
            headerTextArr = ops.headerText.split(';');
            displayFieldsArr = ops.displayFields.split(';');
            var headerStr = "";
            var headerLen = headerTextArr.length;
    
            if (headerLen == 1 || headerLen == 0) {
                var textBox = $(this);
                 
                ops.boxWidth = textBox.css("width");
    
            }
    
            var box = '';
            if (ops.headerText.length == 0) {
    
                box = '<div id="' + ops.boxId + '" style="display:none;' + ops.boxWidth + ';height:' + ops.boxHeight + '"><ul class="suggestBoxItems"></ul></div>';
    
            }
            else {
                for (var i = 0; i < headerLen; i++) {
                    if (i == headerLen - 1) {
                        headerStr += '<span class="headerTextShort">' + headerTextArr[i] + '</span>'
                    }
                    else {
                        headerStr += '<span class="headerTextLong">' + headerTextArr[i] + '</span>'
                    }
                }
                box = '<div id="' + ops.boxId + '" style="display:none;' + ops.boxWidth + ';height:' + ops.boxHeight + '"><div class = "headerText">' + headerStr + '</div><ul class="suggestBoxItems"></ul></div>';
    
            }
            $(this).after(box);
    
            var itemCount = 0;
            $(this).bind('keyup', function(e) {
                var value = $.trim($(this).val());
                if (value.length >= 1) {
                    var position = $(this).position();
    
                    $('#' + ops.boxId).css({ 'display': 'block', 'background': 'white', 'color': 'black', 'position': 'absolute', 'border': "1px solid #D5D5D5", 'left': position.left, 'top': position.top + 22 });
                    var pVal = $(this).val() + "";
                    if (pVal.search('&') >= 0) {
                        pVal = pVal.replace('&', '%26');
                    }
                    if (e.keyCode != 38 && e.keyCode != 40 && e.keyCode != 13 && e.keyCode != 9) {
                        var sugTextBox = $(this);
                        var dataUrl = "/" + ops.controller + "/" + ops.action;
    
                        if (pVal != "") {
                            $.ajax({
                                type: "post",
                                async: true,
                                url: dataUrl,
                                data: "param=" + pVal,
                                dataType: "json",
                                cache: false,
                                timeout: 5000,
                                beforeSend: loading(ops.boxId),
                                error: function(XMLHttpRequest, textStatus, errorThrown) {
                                    alert(textStatus);
                                    $('#' + ops.boxId).slideUp("slow");
                                    $('#' + ops.boxId + ' ul').html('');
                                },
                                success: function(data) {
                                    initBox(ops.boxId, sugTextBox, data, displayFieldsArr, ops.valueField, ops.keyField, ops.keyTextBoxName);
                                }
    
                            });
                        }
    
                        itemIndex = 0;
                    }
                    var itemCount = $('#' + ops.boxId + ' ul li').length;
                    switch (e.keyCode) {
                        case 38:
                            if (itemIndex == 0) {
                                itemIndex = itemCount + 1;
                            }
                            if (itemIndex > 1) {
                                $('#' + ops.boxId + ' ul li:nth-child(' + itemIndex + ')').css({ 'background': 'white', 'color': 'black' });
                                itemIndex--;
                            }
    
                            $('#' + ops.boxId + ' ul li:nth-child(' + itemIndex + ')').css({ 'background': '#7AADEB', 'color': 'white' });
                            $(this).val($('#' + ops.boxId + ' ul li:nth-child(' + itemIndex + ')').find('font').text());
                            if (ops.keyTextBoxName != "") {
                                $('#' + ops.keyTextBoxName).val($('#' + ops.boxId + ' ul li:nth-child(' + itemIndex + ')').find('div').text());
                            }
                            break;
                        case 40:
                            if (itemIndex < itemCount) {
                                $('#' + ops.boxId + ' ul li:nth-child(' + itemIndex + ')').css({ 'background': 'white', 'color': 'black' });
                                itemIndex++;
                            }
    
                            $('#' + ops.boxId + ' ul li:nth-child(' + itemIndex + ')').css({ 'background': '#7AADEB', 'color': 'white' });
                            $(this).val($('#' + ops.boxId + ' ul li:nth-child(' + itemIndex + ')').find('font').text());
                            if (ops.keyTextBoxName != "") {
                                $('#' + ops.keyTextBoxName).val($('#' + ops.boxId + ' ul li:nth-child(' + itemIndex + ')').find('div').text());
                            }
                            break;
                        case 13:
                            if (itemIndex > 0 && itemIndex <= itemCount) {
                                $(this).val($('#' + ops.boxId + ' ul li:nth-child(' + itemIndex + ')').find('font').text());
                                if (ops.keyTextBoxName != "") {
                                    $('#' + ops.keyTextBoxName).val($('#' + ops.boxId + ' ul li:nth-child(' + itemIndex + ')').find('div').text());
                                }
                                $('#' + ops.boxId).slideUp("fast");
                                $('#' + ops.boxId + ' ul').html('');
                                eval(ops.callBack);
                            }
                            break;
                        default:
                            break;
                    }
                }
                else {
    
                    $('#' + ops.boxId).slideUp("fast");
                    $('#' + ops.boxId + ' ul').html('');
                }
            });
            $(this).blur(function() {
                var tempLi = $('#' + ops.boxId + ' ul li:nth-child(1)');
    
                if (itemIndex == 0 && tempLi != undefined) {
    
                    $(this).val(tempLi.find('font').text());
                    if (ops.keyTextBoxName != "") {
                        $('#' + ops.keyTextBoxName).val(tempLi.find('div').text());
                    }
                    itemIndex = 1;
                }
                if ($('#' + ops.boxId + ' ul').html() != '') {
                    eval(ops.callBack);
                }
    
    
                $('#' + ops.boxId).slideUp("fast");
                $('#' + ops.boxId + ' ul').html('');
            });
    
    
        };
    
        function loading(boxId) {
            $('#' + boxId + ' ul').html('<img alt="loading" src="/Scripts/SuggestBox/loading.gif"/>');
    
        }
        function initBox(boxId, obj, data, displayFieldsArr, valueField, keyField, keyTextBoxName) {
    
            var str = "";
            if (data == undefined || data.Data == undefined || data.Data.length == 0) {
                $('#' + boxId + ' ul').html('<div class="noRecordsTip">No records found<div>');
            }
            else {
    
                for (var i = 0; i < data.Data.length; i++) {
                    var fieldStr = "";
                    for (var j = 0; j < displayFieldsArr.length; j++) {
                        if (displayFieldsArr[j] == valueField) {
                            if (j == 0 || j != displayFieldsArr.length - 1) {
                                fieldStr += "<font class='singleField'>" + data.Data[i][displayFieldsArr[j]] + "</font>";
                            }
                            else {
                                fieldStr += "<font>" + data.Data[i][displayFieldsArr[j]] + "</font>";
    
                            }
                        }
                        else {
                            var tempValue = data.Data[i][displayFieldsArr[j]];
    
                            if (tempValue.length > 16) {
                                tempValue = tempValue.substr(0, 16) + "...";
                            }
                            fieldStr += "<span class='commonFields'>" + tempValue + "</span>";
                        }
                    }
                    if (keyField != "") {
                        fieldStr += "<div style = 'display:none;'>" + data.Data[i][keyField] + "</div>";
                    }
    
                    str += "<li>" + fieldStr + "</li>";
                }
                $('#' + boxId + ' ul').html(str);
            }
    
            if (data != undefined && data.Data != undefined && data.Data.length == 1) {
                var tempLi = $('#' + boxId + ' ul li');
                obj.val(tempLi.find('font').text());
                if (keyTextBoxName != "") {
                    $('#' + keyTextBoxName).val(tempLi.find('div').text());
                }
                itemIndex = 1;
            }
            $('#' + boxId + ' ul li').each(function() {
                $(this).bind('click', function() {
                    obj.val($(this).find('font').text());
                    if (keyTextBoxName != "") {
                        $('#' + keyTextBoxName).val($(this).find('div').text());
                    }
                    eval(ops.callBack);
                    $('#' + boxId).slideUp("fast");
    
                });
            });
    
            $('#' + boxId + ' ul li').each(function() {
                $(this).hover(
                    function() {
                        $('#' + boxId + ' ul li:nth-child(' + itemIndex + ')').css({ 'background': 'white', 'color': 'black' });
                        itemIndex = $('#' + boxId + ' ul li').index($(this)[0]) + 1;
                        $(this).css({ 'background': '#7AADEB', 'color': 'white' });
                        obj.val($(this).find('font').text());
                        if (keyTextBoxName != "") {
                            $('#' + keyTextBoxName).val($(this).find('div').text());
                        }
    
                    },
                    function() {
                        $(this).css({ 'background': 'white', 'color': 'black' });
                    }
                );
            });
        };
    })(jQuery);

    在View里面需要Import我们写的扩展类所在的命名空间,<%@ Import Namespace="HtmlHelperExt" %>

    以及引入相关的js、css(extension.suggestbox.js 和 jquery-1.4.1.js 和 SugBoxStyle.css)

    复制代码
    <div>
           <% IDictionary<string, object> htmlAttributes = new Dictionary<string, object>(); htmlAttributes.Add("style", "198px"); %>
    
           简单单列 <%=Html.SuggestBox("MySuggestBox01", "", "SuggestBox", "Suggest","name","", htmlAttributes)%>
    <br /><br /><br /><br />
          带表头单列  <%=Html.SuggestBox("MySuggestBox02", "", "SuggestBox", "Suggest","关键字","name","name","", htmlAttributes)%>
    
    <br /><br /><br /><br />
           带表头双列 <%=Html.SuggestBox("MySuggestBox03", "", "SuggestBox", "Suggest","编号;关键字","id;name","name","", htmlAttributes)%>
    
    <br /><br /><br /><br />
          带表头双列+回调函数  <%=Html.SuggestBox("MySuggestBox04", "", "SuggestBox", "Suggest", "编号;关键字", "id;name", "name", "id", "MySuggestBox04_ID", "0", "afterSelect()", htmlAttributes)%>
    <span id="tip"></span>
    
    <script type="text/javascript">
        var id = document.getElementById("MySuggestBox04_ID").value;
        document.getElementById("tip").innerHTML = "当前选择的编号是: <font color='red'>" + id + "</font>";
        function afterSelect() {
    
            var id = document.getElementById("MySuggestBox04_ID").value;
             document.getElementById("tip").innerHTML = "当前选择的编号是: <font color='red'>"+id+"</font>";
            
        }
     </script>
        </div>
    复制代码

    结果演示一:简单单列

    结果演示二:带表头单列

    结果演示三:带表头双列

    结果演示四:带表头双列+回调函数(选择一值时将key值赋给指定的Hidden中)

  • 相关阅读:
    Win10安装系统后,提示initializing and establishing link无法启动系统
    CSVN使用入门
    CSVN(SVN)命令入门及使用过程中遇到的错误问题汇总
    CSVN部署安装,实现web管理svn
    xenserver使用快照创建虚拟机,提示eth0 has different mac错误
    开机或者安装系统时提示tsc: Fast TSC calibration failed解决方法
    Nginx——debug的使用
    nginx屏蔽某一ip的访问
    plsql快速入门
    Web02_HTML&CSS
  • 原文地址:https://www.cnblogs.com/freeliver54/p/3179970.html
Copyright © 2011-2022 走看看