UDN-企业互联网技术人气社区

板块导航

浏览  : 320
回复  : 4

[原生js] 原生js实现autocomplete插件

[复制链接]
饼干妹妹的头像 楼主
发表于 2017-1-10 15:45:22 | 显示全部楼层 |阅读模式
  这篇文章主要介绍了原生js实现autocomplete插件的相关资料,需要的朋友可以参考下

  在实际的项目中,能用别人写好的插件实现相关功能是最好不过,为了节约时间成本,因为有的项目比较紧急,没充分时间让你自己来写,即便写了,你还要花大量时间调试兼容性。但是出于学习的目的,你可以利用闲暇时间,自己动手写写,看一些原生js的东西,根据自己的思路做插件,这样能提高水平。
  
  说到autotemplete,好多人都用过,引用autotemplete.js,然后就可以实现在输入框输入值的时候提示下拉选项,类似于百度搜索框那种提示功能,下面就来说说自己的思路。
  
  为输入框添加input事件
  
  1.input事件兼容性代码如下:
  1. AddEvt:function(ele, evt, fn) {
  2.       if (document.addEventListener) {
  3.         ele.addEventListener(evt, fn, false);
  4.       } else if (document.attachEvent) {
  5.         ele.attachEvent('on' + (evt == "input" ? "propertychange" : evt), fn);
  6.       } else {
  7.         ele['on' + (evt == "input" ? "propertychange" : evt)] = fn;
  8.       }
  9.     }
复制代码

  input事件和其他的事件不一样,低版本的ie不支持input事件,只能用propertychange事件,高版本的ie和w3c标准浏览器支持input事件
  
  2.输入事件触发的时候获取数据
  
  这里数据有两种形式,一种是直接设置的对象数组,一种是ajax请求返回数据
  
  这时候我们需要一个ajax请求函数,这里写了一个get请求
  1. get: function(url, paraobj, fn, timeout) {
  2.         var xhr = null;
  3.         try {

  4.          ////兼容firefox,chrom
  5.           if (window.XMLHttpRequest) {
  6.             xhr = new XMLHttpRequest();
  7.           }

  8.          //////兼容IE

  9.          else if (Window.ActiveXObject) {

  10.             xhr = new ActiveXObject("Msxml2.Xmlhttp");
  11.           }
  12.         } catch (e) {
  13.           //TODO handle the exception
  14.           xhr = new ActiveXObject('Microsoft.Xmlhttp');
  15.         }
  16.         xhr.onreadystatechange = function() {
  17.           if (this.readyState == 4 && this.status == 200) {
  18.             fn.call(this, this.responseText);

  19.           } else {
  20.             setTimeout(function() {

  21.                xhr.abort();
  22.             }, timeout);
  23.           }
  24.         };
  25.         var parastr = '';
  26.         parastr += "?";
  27.         for (var prop in paraobj) {
  28.           parastr += prop + "=" + paraobj[prop] + "&";
  29.         }
  30.          xhr.open('get', parastr != "?" ? (url + parastr) : url, true);
  31.          xhr.send();

  32.       }
复制代码

  3. ajax请求成功,且有数据的时候创建下拉框并在下拉框中追加选项       ////创建下拉Div
  
  创建下拉框代码:
  1. createShowDiv: function() {

  2.       ///如果下拉div已存在,删除掉
  3.       var parentNode = this.autoElement.parentNode || this.autoElement.parentElement;
  4.       var childNodes = parentNode.childNodes;
  5.       var showDiv = document.getElementById(this.config.showdivId);
  6.       if (showDiv) {
  7.         parentNode.removeChild(showDiv);
  8.       }
  9.       //创建下拉Div
  10.       var div = document.createElement('div');
  11.       div.id = this.config.showdivId;
  12.       //设置下拉div样式
  13.       var style = this.config.style || {
  14.         width: '200px',
  15.         height: 'auto',
  16.         backgroundColor: '#1c5683',
  17.         cursor: 'pointer',
  18.         display: 'block'
  19.       };<br>     
  20.       for (var prop in style) {
  21.         div.style[prop] = style[prop];
  22.       }
  23.       this.showdiv = div;
  24.     }
复制代码

  追加选项代码:
  1. appendChild: function(data) {
  2.       var self = this;
  3.       var data = data;
  4.       var fragment = document.createDocumentFragment();
  5.       for (var i = 0; i < data.length; i++) {
  6.         var obj = data[i];
  7.         var child = document.createElement('div');
  8.         child.style.width = self.showdiv.style.width;
  9.         child.style.border = '1px';
  10.         child.style.borderStyle = 'solid';
  11.         child.style.borderTopColor = 'white';
  12.         child.setAttribute('key', obj[self.config.valueFiled]);
  13.         child.innerHTML = obj[self.config.textFiled];
  14.         fragment.appendChild(child);
  15.       }
  16.       self.showdiv.appendChild(fragment);
  17.       self.util.insertAfter(self.showdiv, self.autoElement);

  18.       //为下拉框添加点击事件
  19.       self.util.AddEvt(self.showdiv, 'click', function(e) {
  20.         var evt = e || window.event;
  21.         var target = evt.srcElement || evt.target;
  22.         var key = target.getAttribute("key");
  23.         var val = target.innerHTML;
  24.         self.autoElement.value = val;
  25.         self.closeDiv();
  26.         self.config.select.call(self, key, val);
  27.       });
  28.     }
复制代码

  上面说的是主要的几步思路,现在看一下怎么将这些代码封装到一个对象中,让它成为插件。这时候我们用到匿名闭包:
  1. (function(win) {
  2.   var autocomplete= function() {
  3.     this.Init.apply(this, arguments);

  4.   }

  5.   autocomplete.prototype = {

  6.     ////添加相关操作代码

  7.     Init: {}, ///初始化参数

  8.     Render: {},

  9.     createShowDiv: {}, ///创建下拉div

  10.     appendChild: {}, ///在下拉div里面追加显示项

  11.     closeDiv: {}, ////关闭下拉框

  12.     //////工具对象,事件,请求,还有dom节点操作的函数

  13.     util: {

  14.       AddEvt: {}, ///添加事件

  15.       insertAfter: {}, ///在某元素后面追加元素

  16.         get: {} //// Ajax get请求

  17.     }

  18.   }

  19.   win.Autocomplete= function(paraobj) {
  20.     new autocomplete(paraobj).Render();
  21.   }
  22. })(window)
复制代码

  主体的代码添加好了,我们把具体的实现代码展示出来:
  1. (function(win) {
  2.   var autocomplete = function () {
  3.     this.Init.apply(this, arguments);
  4.   }
  5.   autocomplete.prototype = {
  6.     Init: function() {
  7.       var args = Array.prototype.slice.call(arguments);
  8.       if (args && args.length > 0) {
  9.         var config = args[0];
  10.         var getType = Object.prototype.toString;
  11.         if (config && getType.call(config) == "[object Object]") {
  12.           //       this.config = config;
  13.           this.config = config || {
  14.             id: '', //控件id
  15.             data: [], //数据
  16.             textFiled: '', //显示的文字的属性名
  17.             valueFiled: '', //获取value的属性名
  18.             style: {}, //显示的下拉div的样式设置
  19.             url: '', //ajax请求的url
  20.             paraName:'name',//ajax请求的参数
  21.             select: function() {}, //选择选项时触发的事件,
  22.             showdivId: '' //下拉选择区域的id
  23.           };
  24.         }
  25.       }
  26.     },
  27.     Render: function() {
  28.       var self = this;
  29.       if (self.config) {
  30.         var autoElement = document.getElementById(self.config.id);
  31.         this.autoElement = autoElement;
  32.         if (autoElement) {
  33.           self.util.AddEvt(this.autoElement, 'input', function() {
  34.             try {
  35.               if (autoElement.value) {
  36.                 ////ajax请求获取数据的方式
  37.                 if (self.config.url && !self.config.data) {
  38.                   var paraobj = {};
  39.                   paraobj[self.config.paraName] = autoElement.value;
  40.                   self.util.get(self.config.url, paraobj, function (data) {
  41.                     self.createShowDiv();
  42.                     self.appendChild(eval('(' + data + ')'));
  43.                   }, 10000);
  44.                 }
  45.                 ////直接设置对象数组的形式
  46.                 else if
  47.                   (!self.config.url && self.config.data) {
  48.                   self.createShowDiv();
  49.                   self.appendChild(self.config.data);
  50.                 }

  51.               } else {
  52.                 self.closeDiv();
  53.               }

  54.             } catch (e) {
  55.               //TODO handle the exception
  56.               alert(e);
  57.             }
  58.           });
  59.         }

  60.       }
  61.     },
  62.     ////创建下拉Div
  63.     createShowDiv: function() {

  64.       ///如果下拉div已存在,删除掉
  65.       var parentNode = this.autoElement.parentNode || this.autoElement.parentElement;
  66.       var childNodes = parentNode.childNodes;
  67.       var showDiv = document.getElementById(this.config.showdivId);
  68.       if (showDiv) {
  69.         parentNode.removeChild(showDiv);
  70.       }
  71.       //创建下拉Div
  72.       var div = document.createElement('div');
  73.       div.id = this.config.showdivId;
  74.       //设置下拉div样式
  75.       var style = this.config.style || {
  76.         width: '200px',
  77.         height: 'auto',
  78.         backgroundColor: '#1c5683',
  79.         cursor: 'pointer',
  80.         display: 'block'
  81.       };
  82.       for (var prop in style) {
  83.         div.style[prop] = style[prop];
  84.       }
  85.       this.showdiv = div;
  86.     },
  87.     ///在下拉div里面追加显示项
  88.     appendChild: function(data) {
  89.       var self = this;
  90.       var data = data;
  91.       var fragment = document.createDocumentFragment();
  92.       for (var i = 0; i < data.length; i++) {
  93.         var obj = data[i];
  94.         var child = document.createElement('div');
  95.         child.style.width = self.showdiv.style.width;
  96.         child.style.border = '1px';
  97.         child.style.borderStyle = 'solid';
  98.         child.style.borderTopColor = 'white';
  99.         child.setAttribute('key', obj[self.config.valueFiled]);
  100.         child.innerHTML = obj[self.config.textFiled];
  101.         fragment.appendChild(child);
  102.       }
  103.       self.showdiv.appendChild(fragment);
  104.       self.util.insertAfter(self.showdiv, self.autoElement);

  105.       //为下拉框添加点击事件
  106.       self.util.AddEvt(self.showdiv, 'click', function(e) {
  107.         var evt = e || window.event;
  108.         var target = evt.srcElement || evt.target;
  109.         var key = target.getAttribute("key");
  110.         var val = target.innerHTML;
  111.         self.autoElement.value = val;
  112.         self.closeDiv();
  113.         self.config.select.call(self, key, val);
  114.       });
  115.     },
  116.     ////关闭下拉框
  117.     closeDiv: function () {
  118.       if (this.showdiv) {
  119.         this.showdiv.style.display = 'none';
  120.       }

  121.     }
  122.     ,
  123.     util: {
  124.       ///添加事件
  125.       AddEvt: function(ele, evt, fn) {
  126.         if (document.addEventListener) {
  127.           ele.addEventListener(evt, fn, false);
  128.         } else if (document.attachEvent) {
  129.           ele.attachEvent('on' + (evt == "input" ? "propertychange" : evt), fn);
  130.         } else {
  131.           ele['on' + (evt == "input" ? "propertychange" : evt)] = fn;
  132.         }
  133.       },
  134.       ///在某元素后面追加元素
  135.       insertAfter: function(ele, targetELe) {
  136.         var parentnode = targetELe.parentNode || targetELe.parentElement;
  137.         if (parentnode.lastChild == targetELe) {
  138.           parentnode.appendChild(ele);
  139.         } else {
  140.           parentnode.insertBefore(ele, targetELe.nextSibling);
  141.         }
  142.       },
  143.       ///Get请求
  144.       get: function(url, paraobj, fn, timeout) {
  145.         var xhr = null;
  146.         try {
  147.           if (window.XMLHttpRequest) {
  148.             xhr = new XMLHttpRequest();
  149.           } else if (Window.ActiveXObject) {

  150.             xhr = new ActiveXObject("Msxml2.Xmlhttp");
  151.           }
  152.         } catch (e) {
  153.           //TODO handle the exception
  154.           xhr = new ActiveXObject('Microsoft.Xmlhttp');
  155.         }
  156.         xhr.onreadystatechange = function() {
  157.           if (this.readyState == 4 && this.status == 200) {
  158.             fn.call(this, this.responseText);

  159.           } else {
  160.             setTimeout(function() {

  161.                xhr.abort();
  162.             }, timeout);
  163.           }
  164.         };
  165.         var parastr = '';
  166.         parastr += "?";
  167.         for (var prop in paraobj) {
  168.           parastr += prop + "=" + paraobj[prop] + "&";
  169.         }
  170.          xhr.open('get', parastr != "?" ? (url + parastr) : url, true);
  171.          xhr.send();

  172.       }
  173.     }
  174.   }

  175.   win.AutoComplete = function (paraobj) {
  176.     new autocomplete(paraobj).Render();

  177.   }

  178. })(window)
复制代码

  下面是使用的代码
  
  页面调用
  1. window.onload = function () {
  2.   AutoComplete({
  3.     id: 'txtTest', //控件id
  4.     url: '/Home/Test4', //数据
  5.     paraName:'name',
  6.     textFiled: 'name', //显示的文字的属性名
  7.     valueFiled: 'id', //获取value的属性名
  8.     //         style: {}, //显示的下拉div的样式设置
  9.     //           url: '', //ajax请求的url
  10.     select: function (val, text) {
  11.       alert(val + '---' + text);
  12.     }, //选择选项时触发的事件,
  13.     showdivId: 'showDIv' //下拉选择区域的id});
  14.   });

  15. }
复制代码

  后台代码如下,这里我用的是mvc
  1. public JsonResult Test4(string  name)
  2. {
  3.   var list=new List<Student>();
  4.   list.Add(new Student { id="1",name="aaaaa"});
  5.   list.Add(new Student { id = "2", name = "aacc" });

  6.   list.Add(new Student { id = "3", name = "aabb" });
  7.   list.Add(new Student { id = "4", name = "bbcc" });

  8.   if (!string.IsNullOrEmpty(name))
  9.   {
  10.     list = list.Where(p => p.name.Contains(name)).ToList();
  11.   }
  12.   return Json(list,JsonRequestBehavior.AllowGet);
  13. }
复制代码

  现在基本的功能实现和调用讲完了,从开始到最后的过程是比较麻烦的,每个方法都是一步步实现,没有引用其他的库,要考虑到各个浏览器的兼容性。
  
  以上就是本文的全部内容,希望对大家的学习有所帮助。
发表于 2017-1-10 15:45:50 | 显示全部楼层
鄙视楼下的顶帖没我快,哈哈
使用道具 举报

回复

发表于 2017-1-10 15:45:51 | 显示全部楼层
无论是不是沙发都得回复下
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部