原生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纯原生的写法啦. ...
随机推荐
- CLR via C# 摘要一:托管程序的执行模型
托管程序的执行模型大致如下: 编译源代码为程序集(dll或exe文件),程序集包括了记录相关信息的元数据和IL代码 执行程序集文件时,启动CLR,JIT负责把IL编译为本地代码并执行 IL是微软推出的 ...
- DataTable的orderby有关问题
在网上找了一个在后台重新对DataTable排序的方法(之所以不在数据库是因为我生成的是报表,写了存储过程用的表变量,order by也要用变量,死活拼不起来,sql能力没过关,动态sql也试了) s ...
- bzoj2693--莫比乌斯反演+积性函数线性筛
推导: 设d=gcd(i,j) 利用莫比乌斯函数的性质 令sum(x,y)=(x*(x+1)/2)*(y*(y+1)/2) 令T=d*t 设f(T)= T可以分块.又由于μ是积性函数,积性函数的约束和 ...
- Scrapy开发指南
一.Scrapy简介 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中. Scrapy基于事件驱动网络框架 Twis ...
- python之最强王者(8)——字典(dictionary)
1.Python 字典(Dictionary) 字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包 ...
- Java使用实现面向对象编程:第七章集合框架的解读=>重中之重
对于集合框架,是非常重要的知识,是程序员必须要知道的知识点. 但是我们为什么要引入集合框架呢? 我们之前用过数组存储数据,但是采用数组存储存在了很多的缺陷.而现在我们引用了集合框架,可以完全弥补了数组 ...
- 初识IOS,Label控件的应用。
初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...
- Android开发者的Kotlin:书
原文标题:Kotlin for Android Developers: The book 原文链接:http://antonioleiva.com/kotlin-android-developers/ ...
- React Native 之生命周期
前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...
- (八)Eclipse创建Maven项目运行mvn命令
1.Eclipse创建Maven项目 使用Eclipse创建一个Maven项目非常的简单,选择菜单项File>New>Other(也可以在项目结构空白处右击鼠标键),在弹出的对话框中选择M ...