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. 第一个简单的android项目

    开发平台:windows7+Eclipse+andriod SDK(24.0)+ADT(23.0.4).这个环境的搭建在前一篇文章(Mobile testing下的appium测试)里面已经描述了. ...

  2. e2e 自动化集成测试 架构 实例 WebStorm Node.js Mocha WebDriverIO Selenium Step by step (六) 自动化测试结构小节

    上一篇‘e2e 自动化集成测试 架构 京东 商品搜索 实例 WebStorm Node.js Mocha WebDriverIO Selenium Step by step (五) 如何让窗体记录登录 ...

  3. Claim-based-security for ASP.NET Web APIs using DotNetOpenAuth

    Recently I worked with a customer assisting them in implementing their Web APIs using the new ASP.NE ...

  4. C++ 编程第二章小结

    switch()用法的注意事项 1:switch语句中的表达式只能是整形数据,字符型数据和枚举型数据,case后面的产量表达式的类型必须与switch括号后面的类型相匹配 2:各个case(包括def ...

  5. ORA-15124 数据库启动阶段报错

    重新进行启动数据库的时候报错: SQL> startup nomount; ORA-15124: ASM file name '+KEL/ipap/controlfile/control02.c ...

  6. 安装CPqD/ofdissector遭遇的错误

    为了安装支持openflow1.3的wireshark插件,在下载了ofdissector.git,并进入了其src目录后,执行scons install,出现如下错误: util/FieldMana ...

  7. [Hive - LanguageManual] DML: Load, Insert, Update, Delete

    LanguageManual DML Hive Data Manipulation Language Hive Data Manipulation Language Loading files int ...

  8. Android与Mysql服务器通信

    需求:在手机端读取蓝牙传输过来的数据,然后发送到mysql 安卓前期版本可以直接使用mysql connector, 现在只能通过访问url传递数据了. 服务器端写php脚本,接受发送过来的url请求 ...

  9. fedora 安装python mysql

    如果你服务器环境允许yum,安装MySQL-python模块就很简单了. 如果直接安装不行,先 安装MySQL-devel后正常运行 yum install mysql-devel yum insta ...

  10. 【bz2594】水管局长数据加强版

    题意: 给出一张n节点.m条代权无向边的无向联通图 和q个任务 1:询问一条x到y的路径 并使路径上最大权值最小 要求输出路径上最大权值 2:宣布x到y的路径报废题目保证该图永远联通 题解: 这是道凶 ...