在实际的项目中,能用别人写好的插件实现相关功能是最好不过,为了节约时间成本,因为有的项目比较紧急,没充分时间让你自己来写,即便写了,你还要花大量时间调试兼容性。但是出于学习的目的,你可以利用闲暇时间,自己动手写写,看一些原生js的东西,根据自己的思路做插件,这样能提高水平。

说到autotemplete,好多人都用过,引用autotemplete.js,然后就可以实现在输入框输入值的时候提示下拉选项,类似于百度搜索框那种提示功能,下面就来说说自己的思路。

  1. 为输入框添加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插件的更多相关文章

  1. 原生js日期时间插件鼠标点击文本框弹出日期时间表格选择日期时间

    原文出处 (这是我从互联网上搜来的,感觉能满足各方面的需求.个人感觉挺不错的,所以后期修改了一下向大家推荐!) 效果图: html代码: <!DOCTYPE html PUBLIC " ...

  2. 原生JS封装Ajax插件(同域&&jsonp跨域)

    抛出一个问题,其实所谓的熟悉原生JS,怎样的程度才是熟悉呢? 最近都在做原生JS熟悉的练习... 用原生Js封装了一个Ajax插件,引入一般的项目,传传数据,感觉还是可行的...简单说说思路,如有不正 ...

  3. 原生js版分页插件

    之前我在自己的博客里发表了一篇用angularJs自定义指令实现的分页插件,今天简单改造了一下,改成了原生JavaScript版本的分页插件,可以自定义一些简单配置,特此记录下来.如有不足之处,欢迎指 ...

  4. 最简单的原生js和jquery插件封装

    最近在开发过程中用别人的插件有问题,所以研究了一下,怎么封装自己的插件. 如果是制作jquery插件的话.就将下面的extend方法换成  $.extend 方法,其他都一样. 总结一下实现原理: 将 ...

  5. 分享一个自己写的基于canvas的原生js图片爆炸插件

    DEMO访问地址: https://bupt-hjm.github.io/BoomGo/博客地址: http://bupt-hjm.github.io/2016/07/10/boom/插件及使用方法地 ...

  6. 原生JS实现"旋转木马"效果的图片轮播插件

    一.写在最前面 最近都忙一些杂七杂八的事情,复习软考.研读经典...好像都好久没写过博客了... 我自己写过三个图片轮播,一个是简单的原生JS实现的,没有什么动画效果的,一个是结合JQuery实现的, ...

  7. 纯原生js移动端图片压缩上传插件

    前段时间,同事又来咨询一个问题了,说手机端动不动拍照就好几M高清大图,上传服务器太慢,问问我有没有可以压缩图片并上传的js插件,当然手头上没有,别慌,我去网上搜一搜. 结果呢,呵呵...诶~又全是基于 ...

  8. 纯原生js移动端城市选择插件

    接着上一篇纯js移动端日期选择插件,话说今天同事又来咨询省市县联动的效果在移动端中如何实现,还是老样子,百度上一搜,诶~又全是基于jquery.zepto的,更加可恨的是大多数都是PC版的,三个sel ...

  9. 原生JS插件(超详细)

    作为一个前端er,如果不会写一个小插件,都不好意思说自己是混前端界的.写还不能依赖jquery之类的工具库,否则装得不够高端.那么,如何才能装起来让自己看起来逼格更高呢?当然是利用js纯原生的写法啦. ...

随机推荐

  1. 最适合作为Java基础面试题之Singleton模式

    看似只是最简单的一种设计模式,可细细挖掘,static.synchronized.volatile关键字.内部类.对象克隆.序列化.枚举类型.反射和类加载机制等基础却又不易理解透彻的Java知识纷纷呼 ...

  2. Python黑帽编程 3.4 跨越VLAN

    Python黑帽编程 3.4 跨域VLAN VLAN(Virtual Local Area Network),是基于以太网交互技术构建的虚拟网络,既可以将同一物理网络划分成多个VALN,也可以跨越物理 ...

  3. [占位-未完成]scikit-learn一般实例之十二:用于RBF核的显式特征映射逼近

    It shows how to use RBFSampler and Nystroem to approximate the feature map of an RBF kernel for clas ...

  4. NSwagStudio for Swagger Api

    本案例主要说明如何使用NSwag 工具使用桌面工具快速生成c# 客户端代码.快速的访问Web Api. NSwagStudio 下载地址 比较强大.可以生成TypeScript.WebApi Cont ...

  5. Backbone.js 中的Model被Destroy后,不能触发success的一个原因

    下面这段代码中, 当调用destroy时,backbone会通过model中的url,向服务端发起一个HTTP DELETE请求, 以删除后台数据库中的user数据. 成功后,会回调触发绑定到dest ...

  6. MongoDB集群卡死问题

    一年前搭了个MongoDB集群,跑得还算不错,但是有几次遇到过服务卡死的问题.处理起来已经得心应手了,拿来跟大家分享一下: 故障现象: 业务查询缓慢,而且会有连接异常: { "serverU ...

  7. 数据库---实验四 oracle的安全性和完整性控制

    实验内容: (一) 授权 . 以dba用户的身份登陆oracle,创建用户u1+学号后四位,u2+学号后四位. SQL> create user u1_3985 identified by &q ...

  8. AlloyRenderingEngine之Shape

    写在前面 不读文章,只对代码感兴趣可以直接跳转到这里 https://github.com/AlloyTeam/AlloyGameEngine 然后star一下,多谢支持:). 游戏或者应用中,不是所 ...

  9. 一个成功的BI项目实施需要注意哪些?

    BI是所有IT系统中最适合于管理层和决策层使用的信息系统. ERP等各类信息系统中的数据,只有通过BI才能将隐藏在数据中的信息挖掘出来.转化为事实. BI的实施也需要依据企业情况进行“定制”.如何实施 ...

  10. Android调用webservice的例子

    1.需要一个ksoap2-android-assembly-2.5.2-jar-with-dependencies.jar的架包. 2.需要知道webservice的命名空间 // WSDL文档中的命 ...