AutoComplete应该不是很陌生了,网上也有好多开源的js。今天主要的不是研究Autocomplete这个js的实现。今天主要讲的是将这个js做成一插件。那么今天主要用到的

演示性例子

做好了上面准备工作,那我们来开始我们的代码编写。

   1:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   2:  <html xmlns="http://www.w3.org/1999/xhtml">
   3:  <head>
   4:      <title></title>
   5:      <script src="../Scripts/jquery-1.9.1.js" type="text/javascript"></script>
   6:      <!-- 这是从jquery-UI-官网上下载的-->
   7:      <script src="../Scripts/jquery-ui.custom.js" type="text/javascript"></script>
   8:      <link href="../Styles/jquery-ui.css" rel="stylesheet" type="text/css" />
   9:      <script type="text/javascript">
  10:          $(function () {
  11:              var arry = ["cnblogs", "博客园", "hankskfc"];
  12:              $("#Text1").autocomplete({
  13:                  source: arry
  14:              });
  15:          });
  16:      </script>
  17:  </head>
  18:  <body>
  19:      <input id="Text1" type="text" />
  20:  </body>
  21:  </html>

下面是运行结果图:

相信这个应该看着官网的都可以写出来。或者可以参考院里面的一篇文章:jQuery UI Autocomplete 体验

这个自己作为练习倒是可以玩玩的,真正要用到项目中去总显得有点臃肿或者说让人用的不爽。我们希望在适量的配置下,只需要对“<input id="Text1" type="text" />”这个添加少量“属性”就可以自动具备上述功能。

思考与探索

首先我们从“数据”提供方面思考。在此引用下jQuery UI Autocomplete 体验 下的东西。

jQuery UI Autocomplete主要支持字符串Array、JSON两种数据格式。

普通的Array格式没有什么特殊的,如下:

   1:  ["cnblogs","博客园","囧月"]


对于JSON格式的Array,则要求有:label、value属性,如下:

   1:  [{label: "博客园", value: "cnblogs"}, {label: "囧月", value: "囧月"}] 

其中label属性用于显示在autocomplete弹出菜单,而value属性则是选中后给文本框赋的值。

如果没有指定其中一个属性则用另一个属性替代(即value和label值一样),如下:

   1:  [{label: "cnblogs"}, {label: "囧月"}]
   2:  [{value: "cnblogs"}, {value: "囧月"}]

如果label和value都没有指定,则无法用于autocomplete的提示。

另外需要注意,对于从服务器端输出的JSON的key必须用双引号,如下:

   1:  [{"label": "博客园", "value": "cnblogs"}, {"label": "囧月", "value": "囧月"}]

否则可能会出现parsererror错误。

囧月”博主总结的很好,很强大。好了我们知道了autocomplete的支持数据类型,联想下实际项目中一般以List<T>形式得到数据库搜索出来的数据或者其他集合形式这里不一一列举了。

那么这里就有个问题怎么样才可以准换成它支持的Json格式呢,你可以每次都自己手动转。这样会用会让人很不爽,有种砸键盘的感觉。想必大家用过mvc这一类框架,里面Model层的话都会在列上打上一个“特定的标签”-Attribute,这里就引出了另一个技术“反射”。那么就呈上源码:

Attribute

   1:   public class AutoCompleteCustomAttribute : Attribute
   2:      {
   3:          public string ColName { get; private set; }
   4:          public AutoCompleteCustomAttribute(string colName)
   5:          {
   6:              ColName = colName;
   7:          }
   8:      }

   1:  public class AutoCompleteLabelAttribute : Attribute
   2:      {
   3:      }

   1:   public class AutoCompleteValueAttribute : Attribute
   2:   {
   3:   }

反射实现ToJson

   1:  public static class ConvertLib
   2:      {
   3:          public static string ConvertToAutoJson<T>(IList<T> instance) where T : new()
   4:          {
   5:              const string result = "[{0}]";
   6:              var type = typeof(T);
   7:              var sb = new StringBuilder();
   8:              foreach (var ins in instance)
   9:              {
  10:                  var label = string.Empty;
  11:                  var value = string.Empty;
  12:                  var custom = string.Empty;
  13:                  sb.Append("{");
  14:                  #region Body
  15:                  foreach (var prop in type.GetProperties())
  16:                  {
  17:                      var attrLabels = prop.GetCustomAttributes(typeof(AutoCompleteLabelAttribute), true);
  18:                      var hasLabel = attrLabels.Length > 0;
  19:                      if (hasLabel)
  20:                      {
  21:                          label = prop.GetValue(ins, null).ToString();
  22:                      }
  23:   
  24:                      var attrValues = prop.GetCustomAttributes(typeof(AutoCompleteValueAttribute), true);
  25:                      var hasValue = attrValues.Length > 0;
  26:                      if (hasValue)
  27:                      {
  28:                          value = prop.GetValue(ins, null).ToString();
  29:                      }
  30:   
  31:                      var attrCustoms = prop.GetCustomAttributes(typeof(AutoCompleteCustomAttribute), true);
  32:                      var hasCustom = attrCustoms.Length > 0;
  33:                      if (!hasCustom) continue;
  34:                      var attr = attrCustoms[0] as AutoCompleteCustomAttribute;
  35:                      if (attr != null)
  36:                      {
  37:                          custom += "\""+attr.ColName + "\":\"" + prop.GetValue(ins, null) + "\",";
  38:                      }
  39:                  }
  40:                  sb.Append("\"label\":\"" + label + "\",");
  41:                  sb.Append("\"value\":\"" + value + "\"");
  42:                  if (!string.IsNullOrEmpty(custom))
  43:                  {
  44:                      custom = custom.Remove(custom.Length - 1);
  45:                      sb.Append(", " + custom + "");
  46:                  } 
  47:                  #endregion
  48:                  sb.Append("},");
  49:              }
  50:              sb = sb.Remove(sb.Length - 1, 1);
  51:              return string.Format(result, sb);
  52:          }
  53:      }

主要思想:遍历集合的每一个T类型的属性,然后看看每个属性是否包含我们设定的“三个特性”,有则按照格式拼接字符串。

(注意:AutoCompleteLabelAttribute,AutoCompleteValueAttribute按照要的json格式只能出现一次,然而AutoCompleteCustomAttribute可以出现多次。还有要注意的是引号问题即40,41,37行,为此我花费了一天查问题郁闷呢!!)

   1:  //我们就可以这样讲一个集合格式化成我们要的Json字符串。
   2:  //妈妈再也不用担心转Json了~~
   3:  var json = ConvertLib.ConvertToAutoJson(T);

问题二

上文中调用转Json中有个问题:你必须知道要转类型即上文的”T”。由于不知道T,我们要么建立好多个一般处理文件,每个一般处理文件都是向上文一样调用。这又让我们用起来不爽了,凭什么每次要对某个业务自动提示就创建一个一般处理程序呢?很不爽呢~~。

那么我们只好在想一些其他的办法,仔细想想MVC Route的添加。都是在一个类似Global.asax文件添加路径,能不能就这个提供一种思路呢?

无论创建多少个一般处理程序,代码结构基本相似,就缺个知道要处理关于那个业务的搜索。那我们可以写个容器来管理我们要求的业务和执行代码的映射,我们只需要在开始开启网站的时候注册下(Global.asax)。

代码如下:

interface

   1:  public interface IHandleAutoJson
   2:      {
   3:          string GetAutoJson(string term);
   4:      }
 

容器类

   1:   public class AutoCompleteConfig
   2:      {
   3:          /// <summary>
   4:          /// 用来保存配置文件的数据字典eg:["nickname":"product"]
   5:          /// </summary>
   6:          private static readonly Dictionary<string, Type> AutoCompleteDict = new Dictionary<string, Type>();
   7:   
   8:          private static readonly object LockObj = new object();
   9:   
  10:          public static Type GetHandler(string nickName)
  11:          {
  12:              Type typ = null;
  13:              if (AutoCompleteDict.ContainsKey(nickName))
  14:              {
  15:                  typ = AutoCompleteDict[nickName];
  16:              }
  17:              return typ;
  18:          }
  19:   
  20:          public static void AddAutoCompleteHandler(string nickName, Type typ)
  21:          {
  22:              lock (LockObj)
  23:              {
  24:                  if (AutoCompleteDict.ContainsKey(nickName))
  25:                  {
  26:                      AutoCompleteDict[nickName] = typ;
  27:                  }
  28:                  else
  29:                  {
  30:                      AutoCompleteDict.Add(nickName, typ);
  31:                  }
  32:              }
  33:   
  34:          }
  35:   
  36:          public static void RemoveAutoCompleteHandler(string nickName)
  37:          {
  38:              lock (LockObj)
  39:              {
  40:                  AutoCompleteDict.Remove(nickName);
  41:              }
  42:          }
  43:      }

代码很简单,就是对容器的Add,Remove,Select操作进行简单的封装。

然后是注册代码:

   1:  AutoCompleteConfig.AddAutoCompleteHandler("product", typeof(AutoCompleteProduct));

然后我们的只要建立一个一般处理程序,要让它和AutoCompleteConfig发生关系只需要一个工厂就行。

   1:   public class AutoCompleteFactory
   2:      {
   3:          public static IHandleAutoJson GetHandler(string nickName)
   4:          {
   5:              IHandleAutoJson json = null;
   6:              var typ = AutoCompleteConfig.GetHandler(nickName);
   7:              if (typ != null && !typ.IsAbstract && typeof(IHandleAutoJson).IsAssignableFrom(typ))
   8:              {
   9:                  var obj = Activator.CreateInstance(typ) as IHandleAutoJson;
  10:                  json = obj;
  11:              }
  12:              return json;
  13:          }
  14:      }

这样我们的调用形式就变成了:

   1:   var handler = AutoCompleteFactory.GetHandler(nickName);//这里是业务对应别名,也是唯一的。
   2:   if (handler!=null)
   3:   {
   4:        json = handler.GetAutoJson(term);
   5:   }

到这里数据提供应该算差不多了,接下来就应该是js块了。

Js调用形式思考

我们希望的形式只是在“<input id="Text1" type="text" />”添加少量的属性,那这个该如何实现呢。

我们需要哪些属性呢?马上想到的是nickName,因为上文中提到是对应于某个业务的。还有没有呢,还缺个class=“autoC”(这里的可以随便取)。

然后我们只需要:

   1:  $(".autoC").each(function () {.....});

将每个需要的text都绑定autocomplete就可以了。

下面就是js代码:

   1:  //用于动态加载css和javascript
   2:  $.extend({
   3:      includePath: '',
   4:      include: function (file) {
   5:          var files = typeof file == "string" ? [file] : file;
   6:          for (var i = 0; i < files.length; i++) {
   7:              var name = files[i].replace(/^\s|\s$/g, "");
   8:              var att = name.split('.');
   9:              var ext = att[att.length - 1].toLowerCase();
  10:              var isCSS = ext == "css";
  11:              var tag = isCSS ? "link" : "script";
  12:              var attr = isCSS ? " type='text/css' rel='stylesheet' " : " language='javascript' type='text/javascript' ";
  13:              var link = (isCSS ? "href" : "src") + "='" + $.includePath + name + "'";
  14:              if ($(tag + "[" + link + "]").length == 0) $(document.head).append("<" + tag + attr + link + "></" + tag + ">");
  15:          }
  16:      }
  17:  });

用于window onload时候动态绑定每一“<input id="Text1" type="text" />”

   1:  //需要在window.onload时候绑定
   2:  //每个要添加 textbox需要添加属性 class="autoC" nickName="product"
   3:  var BindAutoComplete = (function () {
   4:      var scriptPath = JsConfig.GetConfig("baseUrl") + "Scripts/";
   5:      var stylePath = JsConfig.GetConfig("baseUrl") + "Styles/";
   6:      var handlePath = JsConfig.GetConfig("baseUrl") + "Handle/";
   7:      var bindData = function () {
   8:          $.include([scriptPath + 'jquery-ui.custom.js', stylePath + 'jquery-ui.css']);
   9:   
  10:          $(".autoC").each(function () {
  11:              var nickName = $(this).attr("nickName");
  12:              var url = handlePath + 'AutoComplete.ashx?nick=' + nickName;
  13:              $(this).autocomplete({
  14:                  source: url,
  15:                  minLength: 1,
  16:                  select: function (event, ui) {
  17:                      this.value = ui.item.value;
  18:                  }
  19:              });
  20:          });
  21:      };
  22:   
  23:      return {
  24:          BindData: bindData
  25:      };
  26:  })();

Jsconfig:主要发布到IIS上可能有虚拟路径问题,从而添加了这个。

   1:  //JS配置全局静态类
   2:  var JsConfig = (function () {
   3:      var constants = {
   4:          baseUrl: "http://localhost:3694/"
   5:      };
   6:      var returnObj = {
   7:          GetConfig: function (name) {
   8:              return constants[name];
   9:          }
  10:      };
  11:      return returnObj;
  12:  })();

页面调用

   1:  <script src="../Scripts/jquery-1.9.1.js" type="text/javascript"></script>
   2:  <script src="../JsConfig.js" type="text/javascript"></script>
   3:  <script src="../Scripts/AddScript.js" type="text/javascript"></script>
   4:  <script src="../Scripts/AutoComplete/BindAutoComplete.js" type="text/javascript"></script>
   5:  <script type="text/javascript">
   6:     $(function () {
   7:           BindAutoComplete.BindData();
   8:      });
   9:  </script>

好了一个Autocomplete 插件做好了。

源码整理:

关于AutoComplete整合的更多相关文章

  1. sublime 使用总结

    不管你用什么编辑,sublime是首选编辑器,就是sublime淘汰,但已成为标准.例如:atom,几乎等同于sublime,及其他可以几乎调成到sublime操作方式. 一.常用插件 插件搜索地址: ...

  2. Spring3.0 与 MyBatis框架 整合小实例

    本文将在Eclipse开发环境下,采用Spring MVC + Spring + MyBatis + Maven + Log4J 框架搭建一个Java web 项目. 1. 环境准备: 1.1 创建数 ...

  3. discuz论坛与其它网站登录注册整合

    discuz论坛与其它网站登录注册整合 本文以discuz 7.0.0 php版本的论坛与 .net 2.0的网站注册登录整合为类.没有采用uc_center或第三方插件.以另类的方式实现.此方法实现 ...

  4. layui中使用autocomplete.js

    前言 在网站找了一大圈都是问题没有答案,记录记录谨防踩坑 layui版本:layui-v1.0.9_rls a(https://github.com/devbridge/jQuery-Autocomp ...

  5. java ee,包括js,html,jsp等等知识整合

    为了方便修改和后续的包装套路   首先用户访问的页面从web.xml找到 <welcome-file-list> <welcome-file>index.html</we ...

  6. (jQuery插件)autocomplete插件的简单例子

    1.引入相应的js和css,我用到的时候是在jquery-ui的js里面整合的,ui的css 2.先在html上写一个input <input id="tags" class ...

  7. Javascript - ExtJs - 整合百度文章编辑器

    ExtJs - 整合百度文章编辑器(ExtJs UEditor) 第一步:去官网下载最新版本的UEditor,UEditor下载. 第二步:在编辑器根目录创建一个Extjs-Editor.js,录入以 ...

  8. springboot配置server相关配置&整合模板引擎Freemarker、thymeleaf&thymeleaf基本用法&thymeleaf 获取项目路径 contextPath 与取session中信息

    1.Springboot配置server相关配置(包括默认tomcat的相关配置) 下面的配置也都是模板,需要的时候在application.properties配置即可 ############## ...

  9. Ogre 编辑器一(MyGUI+Ogre整合与主界面)

    在查看Ogre例子时,想看材质要里的纹理,着色器代码都需要每个去查找,非常麻烦.也想看更新每个Ogre里的对象后有什么效果.然后看到Compositor组件与粒子组件时,想到能实时编辑着色器代码实时更 ...

随机推荐

  1. IT版孔乙己(转)

    [不要做学究]回忆孔先生IT版 我关于本文评价:看到这篇文章很多人会生出这样的疑问“这明明是在诋毁钻研技术的人嘛?是不是在宣扬技术无用论?”. 初看这篇文章的时候我也是这样的想法,但是逐步才明白这篇文 ...

  2. HDU 1892-See you(二维BIT)

    题意: 最多1000*1000的方格,各方格开始有一本书 有四种操作:对指定方格把书拿走或向里面放书,从一个方格那一定量的书放到另一个方格,查询给定对角线顶点的坐标的矩形范围内包含的书的总数 分析: ...

  3. HDU 4267-A Simple Problem with Integers(多个BIT)

    题意: 2种操作 1 a b k c 在区间[a,b]中的(i-a)%k==0的位置i上的数+c 2 a 查询位置a的值 输出每次查询的值 分析: 开始想到多维的线段树,但比较麻烦,看了题解才知道,用 ...

  4. ASP.NET导出excel表方法汇总

    asp.net里导出excel表方法汇总  1.由dataset生成 public void CreateExcel(DataSet ds,string typeid,string FileName) ...

  5. 【原】Storm Tutorial

    Storm入门教程 1. Storm基础 Storm Storm主要特点 Storm基本概念 Storm调度器 Storm配置 Guaranteeing Message Processing(消息处理 ...

  6. hadoop 权限错误 Permission denied: user=root, access=WRITE, inode="/":hdfs:super

    关于不能执行Hadoop命令 并报权限问题执行错误1.Permission denied: user=root, access=WRITE, inode="/":hdfs:supe ...

  7. python中yield用法

    在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(constructor). 一.迭代器(iterator) 在Python中,for循环可以用于Python中的任何 ...

  8. MFC最大化显示任务栏

    今天2016-07-23   13:26:24又来处理最大化时,窗口任务栏隐藏的bug. 前面已经用了 MINMAXINFO的结构体: typedef struct { POINT ptReserve ...

  9. elementary os下anaconda的spyder.desktop文件

    [Desktop Entry] Version=1.0 Type=Application Name=Spyder GenericName=Spyder Comment=Scientific PYtho ...

  10. 新网注册域名如何转向其他(如花生壳)DNS(不会报错,已经转入成功)

    最近在玩域名,发现相比较来说,新网的域名注册费用相对廉价好多. 但是我以前是用花生壳的,用惯了花生壳,就觉得新网的域名管理界面很不适应,并不是新网的不好,而是习惯了花生壳. 那么如何将新网注册的域名D ...