javascript实现表格排序 编辑 拖拽 缩放
简单表格排序
可以双击编辑自定义编辑后的规则
可拖动列进行列替换
可推动边框进行列宽度的缩放
<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <htmlxmlns="http://www.w3.org/1999/xhtml"> <head> <metahttp-equiv="Content-Type"content="text/html;charset=gb2312"/> <title>Table</title> </head> <styletype="text/css"> body{font-size:12px} #tab{border-collapse:collapse;} .edit{height:16px;width:98%;background-color:#EFF7FF;font-size:12px;border:0px;} #tabtheadtd{background:url(http://images.cnblogs.com/cnblogs_com/wtcsy/192373/r_t.bmp);color:#183C94;word-break:break-all} #tabtbodytd{overflow:hidden;word-break:break-all;} #tabtd{border:1pxsolid#CECFCE;height:20px;line-height:20px;vertical-align:middle;} #tabtd.tc{text-align:center;} .div{width:10px;height:6px;border:1pxsolid#999999;background-color:#FFFFFF;position:absolute;display:none;} .line{width:2px;background-color:#999999; position:absolute;display:none} .dr{height:100%;width:2px;background:#CECFCE;float:right;margin-right:-1px;cursor:sw-resize} .r{float:right;} .l{float:left;} #tabtheadtd.thover{background-image:url(http://album.hi.csdn.net/app_uploads/wtcsy/20081126/000054336.p.gif);background-repeat:repeat-x;} </style> <body> <tableid="tab" border="0"cellspacing="1"cellpadding="0"> <thead> <tr> <tdwidth="80"class="tc"><spanclass="l">ID</span><divclass="rdr"></div></td> <tdwidth="80"class="tc"><spanclass="l">选中</span><divclass="rdr"></div></td> <td width="130"class="tc"><spanclass="l">姓名</span><divclass="rdr"></div></td> <tdwidth="130"class="tc"><spanclass="l">生日</span><divclass="rdr"></div></td> <tdwidth="220"class="tc"><spanclass="l">备注</span><divclass="rdr"></div></td> </tr> </thead> <tbody> <tr> <tdheight="16">1</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>小三</td> <td>1982-05-27</td> <td>杯具,全是杯具</td> </tr> <tr> <td>3</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>李四</td> <td>1983-06-27</td> <td>恩恩我魔兽技术不错</td> </tr> <tr> <td>2</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>王五</td> <td>1987-05-27</td> <td>波斯王子时之刃还不错</td> </tr> <tr> <td>4</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>赵六</td> <td>1988-05-27</td> <td>我叫赵六</td> </tr> <tr> <td>5</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>朱八</td> <td>1984-05-27</td> <td>洗洗睡吧</td> </tr> <tr> <td>6</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>阿斯多夫</td> <td>1984-06-27</td> <td>阿斯多夫暗室逢灯</td> </tr> <tr> <td>7</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>杯具</td> <td>1984-06-27</td> <td>很多的杯具</td> </tr> <tr> <td>8</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>餐具</td> <td>1984-02-27</td> <td>很多的餐具</td> </tr> <tr> <td>8</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>洗具</td> <td>1984-08-27</td> <td>很多的洗具</td> </tr> <tr> <td>9</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>内牛满面</td> <td>1984-12-27</td> <td>10快一晚</td> </tr> <tr> <td>10</td> <td><inputtype="checkbox"><inputname="ss"type="radio" /></td> <td>犀利哥</td> <td>1984-12-21</td> <td>嘿嘿</td> </tr> </tbody> </table> <scriptlanguage="javascript"> (function(window,undefined){ window.Sys=function(ua){ varb={ ie:/msie/.test(ua)&&!/opera/.test(ua), opera:/opera/.test(ua), safari:/webkit/.test(ua)&&!/chrome/.test(ua), firefox:/firefox/.test(ua), chrome:/chrome/.test(ua) },vMark=""; for(variinb){ if(b[i]){vMark="safari"==i?"version":i;break;} } b.version=vMark&&RegExp("(?:"+vMark+")[\\/:]([\\d.]+)").test(ua)?RegExp.$1:"0"; b.ie6=b.ie&&parseInt(b.version,10)==6; b.ie7=b.ie&&parseInt(b.version,10)==7; b.ie8=b.ie&&parseInt(b.version,10)==8; returnb; }(window.navigator.userAgent.toLowerCase());
window.Sys.ie6&&document.execCommand("BackgroundImageCache",false,true);
window.$=function(Id){ returndocument.getElementById(Id); }; window.addListener=function(element,e,fn){ !element.events&&(element.events={}); element.events[e]&&(element.events[e][addListener.guid++]=fn)||(element.events[e]={'0':fn}); element.addEventListener?element.addEventListener(e,fn,false):element.attachEvent("on"+e,fn); }; window.addListener.guid=1; window.removeListener=function(element,e,fn){ varhandlers=element.events[e],type; if(fn){ for(typeinhandlers) if(handlers[type]===fn){ element.removeEventListener?element.removeEventListener(e,fn,false):element.detachEvent("on"+e,fn); deletehandlers[type]; } }else{ for(typeinhandlers){ element.removeEventListener?element.removeEventListener(e,handlers[type],false):element.detachEvent("on"+e,handlers[type]); deletehandlers[type]; } } }; window.setStyle=function(e,o){ if(typeofo=="string") e.style.cssText=o; else for(variino) e.style[i]=o[i]; };
varslice=Array.prototype.slice; window.Bind=function(object,fun){ varargs=slice.call(arguments).slice(2); returnfunction(){ returnfun.apply(object,args); }; }; window.BindAsEventListener=function(object,fun,args){ varargs=slice.call(arguments).slice(2); returnfunction(event){ returnfun.apply(object,[event||window.event].concat(args)); } }; //copyfromjQ window.Extend=function(){ vartarget=arguments[0]||{},i=1,length=arguments.length,deep=true,options; if(typeoftarget==="boolean"){ deep=target; target=arguments[1]||{}; i=2; } if(typeoftarget!=="object"&&Object.prototype.toString.call(target)!="[objectFunction]") target={}; for(;i<length;i++){ if((options=arguments[i])!=null) for(varnameinoptions){ varsrc=target[name],copy=options[name]; if(target===copy) continue; if(deep&©&&typeofcopy==="object"&&!copy.nodeType){ target[name]=arguments.callee(deep,src||(copy.length!=null?[]:{}),copy); } elseif(copy!==undefined) target[name]=copy; } } returntarget; }; window.objPos=function(o){ varx=0,y=0; do{x+=o.offsetLeft;y+=o.offsetTop;}while((o=o.offsetParent)); return{'x':x,'y':y}; } window.Class=function(properties){ var_class=function(){return(arguments[0]!==null&&this.initialize&&typeof(this.initialize)=='function')?this.initialize.apply(this,arguments):this;}; _class.prototype=properties; return_class; }; window.hasClass =function(element,className){ returnelement.className.match(newRegExp('(\\s|^)'+className+'(\\s|$)')); }; window.addClass =function(element,className){ !this.hasClass(element,className)&&(element.className+=""+className); } window.removeClass=function(element,className){ hasClass(element,className)&&(element.className=element.className.replace(newRegExp('(\\s|^)'+className+'(\\s|$)'),'')); } })(window);
varTable=newClass({ options:{ minWidth:62 }, initialize:function(tab,set){ this.table =tab; this.rows =[]; //里面记录所有tr的引用 this.sortCol =null; //记录哪列正在排序中 this.inputtd =null; //记录哪个td正在被编辑了 this.editconfig={}; //编辑表格的规则和提示 this.thead =tab.getElementsByTagName('thead')[0]; this.theadTds =tab.getElementsByTagName('thead')[0].getElementsByTagName('td');//常常用到的dom集合可以用个属性来引用 this.tbodyTds =tab.getElementsByTagName('tbody')[0].getElementsByTagName('td'); this.closConfig={ on :false, td :null, totd :null }; this.widthConfig={ td :null, nexttd :null, x :0, tdwidth :0, nexttdwidth:0 }; Extend(this,this.options); //不知道原因反正不设置就会乱跳 (Sys.ie6||Sys.chrome)&&(tab.width=tab.offsetWidth) //记录那些checkbox,radio被选中了 ie6在做dom操作的时候不会记住这些状态 if(Sys.ie6){ this.checkbox={}; varcheckboxs=tab.getElementsByTagName('input'),i=0,l=checkboxs.length; for(;i<l;i++) (checkboxs[i].type=="checkbox"||checkboxs[i].type=="radio")&& addListener(checkboxs[i],"click",Bind(this,function(elm,i){ elm.checked==true?(this.checkbox[i]=elm):(deletethis.checkbox[i]); },checkboxs[i],i)); }; vari=0,l=set.length,rows=tab.tBodies[0].rows,d=document,tabTads=tab.getElementsByTagName('td'),length=this.theadTds.length; //编辑用的input this.input=d.createElement('input'); this.input.type="text"; this.input.className='edit'; //用于显示正在拖拽的div this.div=d.body.appendChild(d.createElement('div')); this.div.className="div"; //进行缩放的时候显示的竖线 this.line=d.body.appendChild(d.createElement('div')); this.line.className='line'; this.line.style.top=objPos(tab).y+"px"; //遍历set做一些设置 for(;i<l;i++){ //给需要排序的猎头绑定事件 addListener(this.theadTds[set[i].id],'click',Bind(this,this.sortTable,this.theadTds[set[i].id],set[i].type)); //给需要编辑的表给列定义所需配置 set[i].edit&&(this.editconfig[set[i].id]={rule:set[i].edit.rule,message:set[i].edit.message}); } //把所有的tr放到一个数组用于排序 for(i=0,l=rows.length;i<l;i++) this.rows[i]=rows[i]; //遍历所有的td做一些设置 for(i=0,l=tabTads.length;i<l;i++){ //将头部的td全部做上标记拖拽的时候要用到 i<length&&tabTads[i].setAttribute('clos',i); //将需要编辑的td添加edit属性 i>=length&&this.editconfig[i%length]&&tabTads[i].setAttribute('edit',i%length); } //绑定拖拽和缩放的操作 addListener(this.thead,'mousedown',BindAsEventListener(this,this.dragOrWidth)); //拖拽的时候记录移动到了那列td上 addListener(this.thead,'mouseover',BindAsEventListener(this,this.theadHover)); //唉 addListener(this.thead,'mouseout',BindAsEventListener(this,this.theadOut)); //绑定编辑事件根据e.srcElementore.target去判断是哪个表格被编辑 addListener(tab,'dblclick',BindAsEventListener(this,this.edit)); //当离开input时候保存下修改的内容 addListener(this.input,'blur',Bind(this,this.save,this.input)); }, sortTable:function(td,type){//td为点击的那个元素n为哪一列进行排序type为进行什么类型的排序 varfrag=document.createDocumentFragment(),span=td.getElementsByTagName('span')[0],str=span.innerHTML; if(td===this.sortCol){ this.rows.reverse(); span.innerHTML=str.replace(/.$/,str.charAt(str.length-1)=="↓"?"↑":"↓"); }else{ this.rows.sort(this.compare(td.getAttribute('clos'),type)); span.innerHTML=span.innerHTML+"↑"; this.sortCol!=null&&(this.sortCol.getElementsByTagName('span')[0].innerHTML=this.sortCol.getElementsByTagName('span')[0].innerHTML.replace(/.$/,''));//把之前那列排序的标识去掉 }; for(vari=0,l=this.rows.length;i<l;i++) frag.appendChild(this.rows[i]); this.table.tBodies[0].appendChild(frag); if(Sys.ie6){ for(varsinthis.checkbox) this.checkbox[s].checked=true; } this.sortCol=td; //记录哪一列正在排序中 }, compare:function(n,type){ returnfunction(a1,a2){ varconvert={ int :function(v){returnparseInt(v)}, float :function(v){returnparseFloat(v)}, date :function(v){returnv.toString()}, string:function(v){returnv.toString()} }; !convert[type]&&(convert[type]=function(v){returnv.toString()}); a1=convert[type](a1.cells[n].innerHTML); a2=convert[type](a2.cells[n].innerHTML); returna1==a2?0:a1<a2?-1:1; }; }, edit:function(e){ varelem=this.inputtd=e.srcElement||e.target; if(!elem.getAttribute('edit'))return; this.input.value=elem.innerHTML; elem.innerHTML=""; elem.appendChild(this.input); this.input.focus(); }, save:function(elem){ vareditinfo=this.editconfig[elem.parentNode.getAttribute('edit')],status={ "[objectFunction]":'length'ineditinfo.rule&&editinfo.rule(this.input.value)||false, "[objectRegExp]" :'test'ineditinfo.rule&&editinfo.rule.test(this.input.value)||false }[Object.prototype.toString.call(editinfo.rule)],_self=this; //如果不符合条件 修改提示信息 typeofstatus!="boolean"&&(editinfo.message=status); if(status===true){ this.inputtd.innerHTML=this.input.value; this.inputtd=null; }else{ alert(editinfo.message); //firefox下 直接用input.focus()不会执行 用setTimeout可以执行 setTimeout(function(){_self.input.focus()},0); } }, theadHover :function(e){ varelem=e.srcElement||e.target; if(elem.nodeName.toLowerCase()==='td'&&this.closConfig.on){ this.closConfig.totd=elem.getAttribute('clos'); !hasClass(elem,'thover')&&addClass(elem,'thover'); } }, theadOut:function(e){ varelem=e.srcElement||e.target; if(elem.nodeName.toLowerCase()==='td'&&this.closConfig.on)removeClass(elem,'thover') }, dragOrWidth:function(e){ varelem=e.srcElement||e.target,widthConfig=this.widthConfig; //执行拖拽 if(elem.nodeName.toLowerCase()==='td'){ this.closConfig.td=elem.getAttribute('clos'); addListener(document,'mousemove',BindAsEventListener(this,this.dragMove)); addListener(document,'mouseup',Bind(this,this.dragUp)); this.closConfig.on=true; Sys.ie?this.thead.setCapture(false):e.preventDefault(); } //执行宽度缩放 if(elem.nodeName.toLowerCase()==='div'){ Sys.ie?(e.cancelBubble=true):e.stopPropagation(); //如果是最后一个td里面的div不进行缩放 if(this.theadTds[this.theadTds.length-1]===elem.parentNode)return Sys.ie?this.thead.setCapture(false):e.preventDefault(); widthConfig.x=e.clientX; widthConfig.td=elem.parentNode; widthConfig.nexttd=widthConfig.td.nextSibling; while(widthConfig.nexttd.nodeName.toLowerCase()!="td"){ widthConfig.nexttd=widthConfig.nexttd.nextSibling; }; widthConfig.tdwidth =widthConfig.td.offsetWidth; widthConfig.nexttdwidth=widthConfig.nexttd.offsetWidth; this.line.style.height =this.table.offsetHeight+"px"; addListener(document,'mousemove',BindAsEventListener(this,this.widthMove)); addListener(document,'mouseup',Bind(this,this.widthUp)); } }, dragMove:function(e){ window.getSelection?window.getSelection().removeAllRanges():document.selection.empty(); setStyle(this.div,{display:"block",left:e.clientX+9+"px",top:e.clientY+20+"px"}); }, dragUp:function(){ varclosConfig=this.closConfig,rows=this.table.getElementsByTagName('tr'),td,n,o,i=0,l=rows.length; this.div.style.display="none"; removeListener(document,'mousemove'); removeListener(document,'mouseup'); Sys.ie&&this.thead.releaseCapture(); closConfig.on=false; if(closConfig.totd===null)return; removeClass(this.theadTds[closConfig.totd],'thover'); //在同一列不进行列替换 if(closConfig.td===closConfig.totd)return; //进行列替换如果 if(closConfig.td*1+1===closConfig.totd*1){ n=closConfig.totd; o=closConfig.td; }else{ n=closConfig.td; o=closConfig.totd; } for(;i<l;i++){ td=rows[i].getElementsByTagName('td'); rows[i].insertBefore(td[n],td[o]); } //重新标识表头 for(i=0,l=this.theadTds.length;i<l;i++) this.theadTds[i].setAttribute('clos',i); closConfig.totd=closConfig.td=null; }, widthMove:function(e){ window.getSelection?window.getSelection().removeAllRanges():document.selection.empty(); varwidthConfig=this.widthConfig,x=e.clientX-widthConfig.x,left=e.clientX,clientX=left; if(clientX<widthConfig.x&&widthConfig.x-clientX>widthConfig.tdwidth-this.minWidth){ left=widthConfig.x-widthConfig.tdwidth+this.minWidth; } if(clientX>widthConfig.x&&clientX-widthConfig.x>widthConfig.nexttdwidth-this.minWidth){ left=widthConfig.x+widthConfig.nexttdwidth-this.minWidth; } setStyle(this.line,{display:"block",left:left+"px"}); }, widthUp:function(){ this.line.style.display="none"; varwidthConfig=this.widthConfig,x=parseInt(this.line.style.left)-widthConfig.x; widthConfig.nexttd.style.width=widthConfig.nexttdwidth-x-1+'px'; widthConfig.td.style.width=widthConfig.tdwidth+x-1+'px'; Sys.ie&&this.thead.releaseCapture(); removeListener(document,'mousemove'); removeListener(document,'mouseup'); } }); window.onload=function(){ functioncheckName(val){ if(val.replace(/^\s+$/g,'')==='')return'姓名输入不能为空'; if(val.replace(/^\s+|\s+$/,'').length>10)return'姓名长度不能大于10个字符'; if(!/^[\u4e00-\u9fa5a-z]+$/i.test(val))return'姓名只能输入中文或者是字母'; returntrue; }; functioncheckRemark(val){ if(val.replace(/^\s+$/g,'')==='')return'备注输入不能为空'; if(val.replace(/^\s+|\s+$/,'').length>15)return'备注长度不能大于15个字符'; if(!/^[\u4e00-\u9fa5\w\s]+$/i.test(val))return'备注只能输入中文数字下划线空格'; returntrue; } varset=[ {id:0,type:"int"}, {id:2,type:"string",edit:{rule:checkName,message:''}}, {id:3,type:"date",edit:{rule:/^\d{4}\-\d{2}\-\d{2}$/,message:"按这中格式输入日期1985-02-30"}}, {id:4,type:"string",edit:{rule:checkRemark,message:''}} ]; newTable($("tab"),set); } </script> </body> </html>