原生js实现autocomplete插件
在实际的项目中,能用别人写好的插件实现相关功能是最好不过,为了节约时间成本,因为有的项目比较紧急,没充分时间让你自己来写,即便写了,你还要花大量时间调试兼容性。但是出于学习的目的,你可以利用闲暇时间,自己动手写写,看一些原生js的东西,根据自己的思路做插件,这样能提高水平。
说到autotemplete,好多人都用过,引用autotemplete.js,然后就可以实现在输入框输入值的时候提示下拉选项,类似于百度搜索框那种提示功能,下面就来说说自己的思路。
- 为输入框添加input事件
input事件兼容性代码如下:
AddEvt:function(ele, evt, fn) {
if (document.addEventListener) {
ele.addEventListener(evt, fn, false);
} else if (document.attachEvent) {
ele.attachEvent('on' + (evt == "input" ? "propertychange" : evt), fn);
} else {
ele['on' + (evt == "input" ? "propertychange" : evt)] = fn;
}
}
input事件和其他的事件不一样,低版本的ie不支持input事件,只能用propertychange事件,高版本的ie和w3c标准浏览器支持input事件
2.输入事件触发的时候获取数据
这里数据有两种形式,一种是直接设置的对象数组,一种是ajax请求返回数据
这时候我们需要一个ajax请求函数,这里写了一个get请求
get: function(url, paraobj, fn, timeout) {
var xhr = null;
try {
////兼容firefox,chrom
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
//////兼容IE
else if (Window.ActiveXObject) {
xhr = new ActiveXObject("Msxml2.Xmlhttp");
}
} catch (e) {
//TODO handle the exception
xhr = new ActiveXObject('Microsoft.Xmlhttp');
}
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
fn.call(this, this.responseText);
} else {
setTimeout(function() {
xhr.abort();
}, timeout);
}
};
var parastr = '';
parastr += "?";
for (var prop in paraobj) {
parastr += prop + "=" + paraobj[prop] + "&";
}
xhr.open('get', parastr != "?" ? (url + parastr) : url, true);
xhr.send();
}
3. ajax请求成功,且有数据的时候创建下拉框并在下拉框中追加选项 ////创建下拉Div
创建下拉框代码:
createShowDiv: function() {
///如果下拉div已存在,删除掉
var parentNode = this.autoElement.parentNode || this.autoElement.parentElement;
var childNodes = parentNode.childNodes;
var showDiv = document.getElementById(this.config.showdivId);
if (showDiv) {
parentNode.removeChild(showDiv);
}
//创建下拉Div
var div = document.createElement('div');
div.id = this.config.showdivId;
//设置下拉div样式
var style = this.config.style || {
width: '200px',
height: 'auto',
backgroundColor: '#1c5683',
cursor: 'pointer',
display: 'block'
};
for (var prop in style) {
div.style[prop] = style[prop];
}
this.showdiv = div;
}
追加选项代码:
appendChild: function(data) {
var self = this;
var data = data;
var fragment = document.createDocumentFragment();
for (var i = 0; i < data.length; i++) {
var obj = data[i];
var child = document.createElement('div');
child.style.width = self.showdiv.style.width;
child.style.border = '1px';
child.style.borderStyle = 'solid';
child.style.borderTopColor = 'white';
child.setAttribute('key', obj[self.config.valueFiled]);
child.innerHTML = obj[self.config.textFiled];
fragment.appendChild(child);
}
self.showdiv.appendChild(fragment);
self.util.insertAfter(self.showdiv, self.autoElement);
//为下拉框添加点击事件
self.util.AddEvt(self.showdiv, 'click', function(e) {
var evt = e || window.event;
var target = evt.srcElement || evt.target;
var key = target.getAttribute("key");
var val = target.innerHTML;
self.autoElement.value = val;
self.closeDiv();
self.config.select.call(self, key, val);
});
}
上面说的是主要的几步思路,现在看一下怎么将这些代码封装到一个对象中,让它成为插件。这时候我们用到匿名闭包:
(function(win) {
var autocomplete= function() {
this.Init.apply(this, arguments);
}
autocomplete.prototype = {
////添加相关操作代码
Init: {}, ///初始化参数
Render: {},
createShowDiv: {}, ///创建下拉div
appendChild: {}, ///在下拉div里面追加显示项
closeDiv: {}, ////关闭下拉框
//////工具对象,事件,请求,还有dom节点操作的函数
util: {
AddEvt: {}, ///添加事件
insertAfter: {}, ///在某元素后面追加元素
get: {} //// Ajax get请求
}
}
win.Autocomplete= function(paraobj) {
new autocomplete(paraobj).Render();
}
})(window)
主体的代码添加好了,我们把具体的实现代码展示出来:
(function(win) {
var autocomplete = function () {
this.Init.apply(this, arguments);
}
autocomplete.prototype = {
Init: function() {
var args = Array.prototype.slice.call(arguments);
if (args && args.length > 0) {
var config = args[0];
var getType = Object.prototype.toString;
if (config && getType.call(config) == "[object Object]") {
// this.config = config;
this.config = config || {
id: '', //控件id
data: [], //数据
textFiled: '', //显示的文字的属性名
valueFiled: '', //获取value的属性名
style: {}, //显示的下拉div的样式设置
url: '', //ajax请求的url
paraName:'name',//ajax请求的参数
select: function() {}, //选择选项时触发的事件,
showdivId: '' //下拉选择区域的id
};
}
}
},
Render: function() {
var self = this;
if (self.config) {
var autoElement = document.getElementById(self.config.id);
this.autoElement = autoElement;
if (autoElement) {
self.util.AddEvt(this.autoElement, 'input', function() {
try {
if (autoElement.value) {
////ajax请求获取数据的方式
if (self.config.url && !self.config.data) {
var paraobj = {};
paraobj[self.config.paraName] = autoElement.value;
self.util.get(self.config.url, paraobj, function (data) {
self.createShowDiv();
self.appendChild(eval('(' + data + ')'));
}, 10000);
}
////直接设置对象数组的形式
else if
(!self.config.url && self.config.data) {
self.createShowDiv();
self.appendChild(self.config.data);
}
} else {
self.closeDiv();
}
} catch (e) {
//TODO handle the exception
alert(e);
}
});
}
}
},
////创建下拉Div
createShowDiv: function() {
///如果下拉div已存在,删除掉
var parentNode = this.autoElement.parentNode || this.autoElement.parentElement;
var childNodes = parentNode.childNodes;
var showDiv = document.getElementById(this.config.showdivId);
if (showDiv) {
parentNode.removeChild(showDiv);
}
//创建下拉Div
var div = document.createElement('div');
div.id = this.config.showdivId;
//设置下拉div样式
var style = this.config.style || {
width: '200px',
height: 'auto',
backgroundColor: '#1c5683',
cursor: 'pointer',
display: 'block'
};
for (var prop in style) {
div.style[prop] = style[prop];
}
this.showdiv = div;
},
///在下拉div里面追加显示项
appendChild: function(data) {
var self = this;
var data = data;
var fragment = document.createDocumentFragment();
for (var i = 0; i < data.length; i++) {
var obj = data[i];
var child = document.createElement('div');
child.style.width = self.showdiv.style.width;
child.style.border = '1px';
child.style.borderStyle = 'solid';
child.style.borderTopColor = 'white';
child.setAttribute('key', obj[self.config.valueFiled]);
child.innerHTML = obj[self.config.textFiled];
fragment.appendChild(child);
}
self.showdiv.appendChild(fragment);
self.util.insertAfter(self.showdiv, self.autoElement);
//为下拉框添加点击事件
self.util.AddEvt(self.showdiv, 'click', function(e) {
var evt = e || window.event;
var target = evt.srcElement || evt.target;
var key = target.getAttribute("key");
var val = target.innerHTML;
self.autoElement.value = val;
self.closeDiv();
self.config.select.call(self, key, val);
});
},
////关闭下拉框
closeDiv: function () {
if (this.showdiv) {
this.showdiv.style.display = 'none';
}
}
,
util: {
///添加事件
AddEvt: function(ele, evt, fn) {
if (document.addEventListener) {
ele.addEventListener(evt, fn, false);
} else if (document.attachEvent) {
ele.attachEvent('on' + (evt == "input" ? "propertychange" : evt), fn);
} else {
ele['on' + (evt == "input" ? "propertychange" : evt)] = fn;
}
},
///在某元素后面追加元素
insertAfter: function(ele, targetELe) {
var parentnode = targetELe.parentNode || targetELe.parentElement;
if (parentnode.lastChild == targetELe) {
parentnode.appendChild(ele);
} else {
parentnode.insertBefore(ele, targetELe.nextSibling);
}
},
///Get请求
get: function(url, paraobj, fn, timeout) {
var xhr = null;
try {
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (Window.ActiveXObject) {
xhr = new ActiveXObject("Msxml2.Xmlhttp");
}
} catch (e) {
//TODO handle the exception
xhr = new ActiveXObject('Microsoft.Xmlhttp');
}
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
fn.call(this, this.responseText);
} else {
setTimeout(function() {
xhr.abort();
}, timeout);
}
};
var parastr = '';
parastr += "?";
for (var prop in paraobj) {
parastr += prop + "=" + paraobj[prop] + "&";
}
xhr.open('get', parastr != "?" ? (url + parastr) : url, true);
xhr.send();
}
}
}
win.AutoComplete = function (paraobj) {
new autocomplete(paraobj).Render();
}
})(window)
下面是使用的代码
页面调用
window.onload = function () {
AutoComplete({
id: 'txtTest', //控件id
url: '/Home/Test4', //数据
paraName:'name',
textFiled: 'name', //显示的文字的属性名
valueFiled: 'id', //获取value的属性名
// style: {}, //显示的下拉div的样式设置
// url: '', //ajax请求的url
select: function (val, text) {
alert(val + '---' + text);
}, //选择选项时触发的事件,
showdivId: 'showDIv' //下拉选择区域的id});
});
}
后台代码如下,这里我用的是mvc
public JsonResult Test4(string name)
{
var list=new List<Student>();
list.Add(new Student { id="1",name="aaaaa"});
list.Add(new Student { id = "2", name = "aacc" }); list.Add(new Student { id = "3", name = "aabb" });
list.Add(new Student { id = "4", name = "bbcc" }); if (!string.IsNullOrEmpty(name))
{
list = list.Where(p => p.name.Contains(name)).ToList();
}
return Json(list,JsonRequestBehavior.AllowGet);
}
现在基本的功能实现和调用讲完了,从开始到最后的过程是比较麻烦的,每个方法都是一步步实现,没有引用其他的库,要考虑到各个浏览器的兼容性。如果你有什么疑问,请留言,我会回复。
原生js实现autocomplete插件的更多相关文章
- 原生js日期时间插件鼠标点击文本框弹出日期时间表格选择日期时间
原文出处 (这是我从互联网上搜来的,感觉能满足各方面的需求.个人感觉挺不错的,所以后期修改了一下向大家推荐!) 效果图: html代码: <!DOCTYPE html PUBLIC " ...
- 原生JS封装Ajax插件(同域&&jsonp跨域)
抛出一个问题,其实所谓的熟悉原生JS,怎样的程度才是熟悉呢? 最近都在做原生JS熟悉的练习... 用原生Js封装了一个Ajax插件,引入一般的项目,传传数据,感觉还是可行的...简单说说思路,如有不正 ...
- 原生js版分页插件
之前我在自己的博客里发表了一篇用angularJs自定义指令实现的分页插件,今天简单改造了一下,改成了原生JavaScript版本的分页插件,可以自定义一些简单配置,特此记录下来.如有不足之处,欢迎指 ...
- 最简单的原生js和jquery插件封装
最近在开发过程中用别人的插件有问题,所以研究了一下,怎么封装自己的插件. 如果是制作jquery插件的话.就将下面的extend方法换成 $.extend 方法,其他都一样. 总结一下实现原理: 将 ...
- 分享一个自己写的基于canvas的原生js图片爆炸插件
DEMO访问地址: https://bupt-hjm.github.io/BoomGo/博客地址: http://bupt-hjm.github.io/2016/07/10/boom/插件及使用方法地 ...
- 原生JS实现"旋转木马"效果的图片轮播插件
一.写在最前面 最近都忙一些杂七杂八的事情,复习软考.研读经典...好像都好久没写过博客了... 我自己写过三个图片轮播,一个是简单的原生JS实现的,没有什么动画效果的,一个是结合JQuery实现的, ...
- 纯原生js移动端图片压缩上传插件
前段时间,同事又来咨询一个问题了,说手机端动不动拍照就好几M高清大图,上传服务器太慢,问问我有没有可以压缩图片并上传的js插件,当然手头上没有,别慌,我去网上搜一搜. 结果呢,呵呵...诶~又全是基于 ...
- 纯原生js移动端城市选择插件
接着上一篇纯js移动端日期选择插件,话说今天同事又来咨询省市县联动的效果在移动端中如何实现,还是老样子,百度上一搜,诶~又全是基于jquery.zepto的,更加可恨的是大多数都是PC版的,三个sel ...
- 原生JS插件(超详细)
作为一个前端er,如果不会写一个小插件,都不好意思说自己是混前端界的.写还不能依赖jquery之类的工具库,否则装得不够高端.那么,如何才能装起来让自己看起来逼格更高呢?当然是利用js纯原生的写法啦. ...
随机推荐
- 基于trie树的具有联想功能的文本编辑器
之前的软件设计与开发实践课程中,自己构思的大作业题目.做的具有核心功能,但是还欠缺边边角角的小功能和持久化数据结构,先放出来,有机会一点点改.github:https://github.com/chu ...
- MVC采用Jquery实现局部刷新
该文纯粹属于个人学习,有不足之处请多多指教! 效果图: 单击Detail下面出现详细,效果如下: 为了使操作时两个不同的数据源相互干扰,使用局部视图刷新,代码如下: 首先介绍主页Index代码: @m ...
- [C#项目开源] MongoDB 可视化管理工具 (2011年10月-至今)
正文 该项目从2011年10月开始开发,知道现在已经有整整5年了.MongoDB也从一开始的大红大紫到现在趋于平淡. MongoCola这个工具在一开始定位的时候只是一个Windows版本的工具,期间 ...
- request.getParameter()、request.getInputStream()和request.getReader()
大家经常 用servlet和jsp,但是对 request.getInputStream()和request.getReader()比较陌生.request.getParameter()request ...
- python学习笔记(基础二:注释、用户输入、格式化输出)
注释 单行:# 多行:上下各用3个连续单引号或双引号 3个引号除了多行注释,还可以打印多行 举例: msg = ''' name = "Alex Li" name2 = name ...
- 2016年最新mac下vscode配置golang开发环境支持debug
网上目前还找不到完整的mac下golang环境配置支持,本人配置成功,现在整理分享出来. mac最好装下xcode,好像有依赖关系安装Homebrew打开终端窗口, 粘贴脚本执行/usr/bin/ru ...
- Redis主从复制
大家可以先看这篇文章ASP.NET Redis 开发对Redis有个初步的了解 Redis的主从复制功能非常强大,一个master可以拥有多个slave,而一个slave又可以拥有多个slave,如此 ...
- Windows消息机制
Windows的消息系统是由3个部分组成的: · 消息队列.Windows能够为所有的应用程序维护一个消息队列.应用程序必须从消息队列中获取消息,然后分派给某个窗口.· 消息循环.通过这个循环机制应用 ...
- JavaScript标准参考教材(alpha)--笔记
一.导论 二.基本语法 1.严格来说var a=1与a=1效果不太一样,delete命令无法删除前者. JavaScirpt是一种动态类型语言,也就是说,变量的类型没有限制,可以赋予各种类型的值. J ...
- Visual Studio 2013 Preview 高清多图先睹为快
Visual Studio 2013 Preview已经发布.大家可以下载试用了哦: 选项加载明显比之前版本要快很多.