基于Jquery和Ajax的多选框
哈哈,终于我也在博客园开通博客了,怎么说现在我也算进入it行业了,以后看来要在这里好好开垦一番了。
现在就说说我仿照人才网做的多选框吧,之前做一个项目的时候需要用到基于Ajax的多选框,网上找了一下,发现都不是我想要的,后来发现求职网站上的多选框比较符合我的要求,但是他那是本地缓存的,我想要的是用Ajax请求从数据库获得数据再填充到多选框的,于是我将他修改一番,做出一个基于Jquery和Ajax的通用多选框。
首先用Jquery定义一个没有名称的匿名函数
1 (function ($) { 2 ...... 3 })(jQuery);
匿名函数在js中因为也是对象,所以需要双括号包裹起来,这个结构说明,我使用了匿名函数,并且立刻执行这个匿名函数。在此Jquery匿名函数内,他会自己创建Jquery对象。再啰嗦一下,这个结构和
a=function($) { ...... }; a(jquery);
是等价的。
搭好函数后,需要为此插件定义一些Jquery全局对象,这用到了Jquery的extend扩展方法
//弹出层 $.openLayer = function (p) { var param = $.extend({ returnValue: "", //以,分隔的选取结果id存放的位置id,默认为一个input。 returnText: "", //以,分隔的选取结果文字存放的位置id,可以为span,div等容器。 title: "请选择", //弹出窗口标题 width: 650, //弹出窗口宽度 span_width: { d1: 70 }, //可以自定义每一层级数据项显示宽度,用来对其排版。 url: "", //ajax请求url dragEnable: true //是否允许鼠标拖动 }, p || {});
既然是全局变量,也就是说如果以后有同样名字的Jquery参数,那么原来的参数值将被覆盖。这对于插件开发那是大大有好处呀,就像一个软件的各种设置有默认值,你可以自己更改一样
至此,插件的外壳搭建好了,现在将实现功能。首先定义一个对象,在这个对象里面填充各种将要被调用的函数,包括css插入
init_style: function () { //初始化css var margin = 4; var width = param.width - margin * 5; var css = "<style>"; var aotu = "border:2px groove"; css += "#popupAddr {position:absolute;border:3px ridge;width:" + param.width + "px;background-color:#e3e3e3;z-index:99;box-shadow:5px 5px 5px rgba(0,0,0,0.5)}"; css += "#bodybg {width:100%;position:absolute;top:0;left:0;background-color:#000000;opacity:0.5}"; css += "#heads {font-size:12px}"; css += "#headdiv {color:white;background-color:#3C85ff;font-size:13px;line-height:30px;padding:0 12px;margin:1px;" + aotu + "}"; css += "#close {float:right}"; css += "#selArea {width:" + width + "px;min-height:48px;margin:" + margin + "px;padding:5px;background-color:#f4f4f4;float:left;" + aotu + "}"; $("head").append(css + "</style>"); }
这里不讨论在js里面插入css的缺点,不过有一个好处就是这个插件将只需要调用一个js文件,不需要调用css文件了,另外我一直在想用字符串追加和栈哪个效率高,似乎在不同浏览器表现不一样,这里估且用+=吧;头部初始化
init_Container: function () { //初始化头部和内容容器 var close = "<span id='_cancel' style='cursor:pointer;'>[取消]</span> <span id='_ok' style='cursor:pointer;'>[确定]</span>"; //头部 var htmlDiv = "<div id='heads'><div id='headdiv'><span title='全选/全不选'><input type='checkbox' id='selectAll'/>" + param.title + "</span><span id='close'>" + close + "</span></div>"; //内容容器创建部分 htmlDiv += "<div id='container'><div id='selArea'><div>已选择:</div></div><div id='d1'></div></div></div>"; pop.html(htmlDiv); },
添加数据到容器
add_data: function (targetid) { //添加数据到容器,添加事件,初始化下一层次容器 var data = ''; //返回数据变量 $.ajax({ type: "post", //post方式 url: param.url, //ajax查询url async: false, //同步方式,便于拿到返回数据做统一处理 success: function (d) { //ajax请求成功后返回数据 data = d; } }); //没有数据或者错误,添加提示信息返回 if (data == "") { $("#selArea").append("<span style='color:red;'>获取数据失败!</span>"); return; } var spanWidth = eval("param.span_width." + targetid.attr("id")); //每个数据显示项的宽度 spanWidth = (spanWidth == undefined ? param.span_width.d1 : spanWidth); //没有设置的话,就使用第一个数据容器的值 var inspanWidth = ($.browser.msie) ? 1 : 3; //内部文字和checkbox之间的距离 var dat = data.split(','); //根据设定分隔符对数据做第一次分隔,获得数据项数组 var html = ''; //格式化数据存放容器,为了提高效率,使用了字符串 var ss; //循环获得格式化的显示字符串 for (var i = 0, l = dat.length; i < l; i++) { ss = dat[i].split(':'); //第二次分隔,获得每个数据项中的数据值和显示字符串 html += "<span title='" + dat[i] + "' style='width:" + spanWidth + "px;white-space:nowrap;float:left;'><input type='checkbox' value='" + ss[0] + "'><span style='margin-left:" + inspanWidth + "px;'>" + ss[1] + "</span></span>"; } targetid.html(html); //格式化的html代码放入目标容器 },
原本除了可以填充Ajax获取的数据还可以填充缓存数据的,后来被我去掉了;初始化自启事件
init_event: function () { //绑定已选择框中checkbox的事件,确定,取消事件响应 var selArea = $("#selArea"), d1 = $("#d1"); selArea.delegate('input', 'click', function () { $(this).parent().remove(); d1.find("input[value=" + this.value + "]").attr("checked", false); }); d1.delegate('input', 'click', function () { if (this.checked) { selArea.append($(this).parent().clone().css({ "width": "", "background": "", "border": "" })); } else { selArea.find("input[value=" + this.value + "]").parent().remove(); } }); $("#selectAll").click(function () { selArea.find("input").each(function () { this.click(); }); if (this.checked) { d1.find("input").each(function () { this.click(); }); } }); $("#_cancel").click(function () { bodybg.hide(); pop.hide(); }); $("#_ok").click(function () { var vals = ""; var txts = ""; selArea.find("input").each(function () { vals += "," + this.value; txts += "," + $(this).next().text(); }); fs.set_returnVals(param.returnValue, vals); fs.set_returnVals(param.returnText, txts); bodybg.hide(); pop.hide(); }); },
这里使用Jquery的delegate() 方法,而不是 live(),据说效率高些,因为他不是监听多个子元素的事件,而是监听一个母元素的事件,再判断是哪个子元素,点击确定按钮时value将被赋值给returnValue对应的元素,text将被赋值给returnText对应的元素;
;控件移动方法
move: function () { if (param.dragEnable) { //允许鼠标拖动 var move = false; //移动标记 var ox, oy; //鼠标离控件左上角的相对位置 pop.mousedown(function (e) { move = true; ox = e.pageX - parseInt(pop.css("left")); oy = e.pageY - parseInt(pop.css("top")); }).mousemove(function (e) { if (move) { var x = e.pageX - ox; //移动时根据鼠标位置计算控件左上角的绝对位置 var y = e.pageY - oy; pop.css({ top: y, left: x }); //控件新位置 } }).mouseup(function () { move = false; }); } },
至此,对象声明好了,现在只需要调用声明好的对象里的方法即可
var pop = $("#popupAddr"); //创建一个div元素 var bodybg = $("#bodybg"); //创建背景层 if (pop.length == 0) { fs.init_style(); //初始化样式 pop = $("<div id='popupAddr'></div>"); $("body").append(pop); bodybg = $("<div id='bodybg'></div>"); $("body").append(bodybg); fs.move(); } fs.init_Container(); //弹出层内容 fs.add_data($("#d1")); //添加数据 fs.init_event(); //初始化已选中的项 fs.init_selected(); //让多选框居中显示 var yPos = ($(window).height() - pop.height()) / 2; var xPos = ($(window).width() - pop.width()) / 2; pop.css({ top: yPos, left: xPos }).show(); bodybg.height(document.body.scrollHeight); bodybg.show(); pop.show();
当一个页面多个这种控件时,有些方法是只需要执行一次的,如css插入方法和控件移动方法。
呼呼,终于写完了,用的时候写上
$("xxx").click(function () { $.openLayer({ returnText: "xxx", title: "xxx", returnValue: "xxx", span_width: { d1: 120 }, url: "/xxx/xxx" }); });
此控件接收的数据格式是"xxx:xxx,xxx:xxx...",即是vluae:text然后用逗号分开。另外我是加了jquery-1.7.1.min.js的,贴个效果图吧,源码