javascript实现表格排序 编辑 拖拽 缩放

简单表格排序

可以双击编辑 自定义编辑后的 规则

可拖动列进行列替换

可推动边框进行列宽度的缩放

代码如下:
"> "> Table
Box">Box">Box">Box">Box">Box">Box">Box">Box">Box">Box">

window.Sys.ie6&&document.execCommand("BackgroundImageCache",false,true);

window.$ = function(Id){ return document.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,fn){ var handlers = element.events[e],type; if(fn){ for(type in handlers) if(handlers[type]===fn){ element.removeEventListener?element.removeEventListener(e,false):element.detachEvent("on" + e,fn); delete handlers[type]; } }else{ for(type in handlers){ element.removeEventListener?element.removeEventListener(e,handlers[type],handlers[type]); delete handlers[type]; } } }; window.setStyle = function(e,o){ if(typeof o=="string") e.style.csstext=o; else for(var i in o) e.style[i] = o[i]; };

var slice = Array.prototype.slice; window.Bind = function(object,fun) { var args = slice.call(arguments).slice(2); return function() { return fun.apply(object,args); }; }; window.BindAsEventListener = function(object,fun,args) { var args = slice.call(arguments).slice(2); return function(event) { return fun.apply(object,[event || window.event].concat(args)); } }; //copy from jQ window.Extend = function(){ var target = arguments[0] || {},i = 1,length = arguments.length,deep = true,options; if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; i = 2; } if ( typeof target !== "object" && Object.prototype.toString.call(target)!="[object Function]") target = {}; for(;icopy = options[ name ]; if ( target === copy ) continue; if ( deep && copy && typeof copy === "object" && !copy.nodeType ){ target[ name ] = arguments.callee( deep,src || ( copy.length != null ? [ ] : { } ),copy ); } else if(copy !== undefined) target[ name ] = copy; } } return target; }; window.objpos = function(o){ var x = 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){ return element.className.match(new RegExp('()); } ; 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(new RegExp('( ')); } })(window);

var Table = new Class({ 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 = {}; var checkBoxs = tab.getElementsByTagName('input'),i=0,l=checkBoxs.length; for(;iBoxs[i].type=="checkBox"||checkBoxs[i].type=="radio")&& addListener(checkBoxs[i],"click",Bind(this,function(elm,i){ elm.checked==true?(this.checkBox[i] = elm):(delete this.checkBox[i]); },checkBoxs[i],i)); }; var i=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.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//遍历所有的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',this.theadHover));

//唉
addListener(this.thead,'mouSEOut',this.theadOut));

//绑定编辑事件 根据e.srcElement or e.target去判断是哪个表格被编辑
addListener(tab,'dblclick',this.edit));

//当离开input时候保存下修改内容
addListener(this.input,'blur',this.save,this.input));
},
sortTable :function(td,type){ //td为点击的那个元素 n 为哪一列进行排序 type为进行什么类型的排序
var frag=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(var i=0,l=this.rows.length;i<l;i++)
frag.appendChild(this.rows[i]);
this.table.tBodies[0].appendChild(frag);
if(Sys.ie6){
for(var s in this.checkBox)
this.checkBox[s].checked = true;
}
this.sortCol = td; //记录哪一列正在排序中
},
compare :function(n,type){
return function (a1,a2){
var convert ={
int : function(v){return parseInt(v)},
float : function(v){return parseFloat(v)},
date : function(v){return v.toString()},
string : function(v){return v.toString()}
};
!convert[type]&&(convert[type]=function(v){return v.toString()});
a1 =converttype;
a2 =converttype;
return a1==a2?0:a1<a2?-1:1;
};
},
edit: function(e){
var elem = 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){
var editinfo=this.editconfig[elem.parentNode.getAttribute('edit')],status={
"[object Function]" : 'length' in editinfo.rule&&editinfo.rule(this.input.value)||false,
"[object RegExp]" : 'test' in editinfo.rule&&editinfo.rule.test(this.input.value)||false
}[Object.prototype.toString.call(editinfo.rule)],_self=this;
//如果不符合条件 修改提示信息
typeof status != "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){
var elem = 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){
var elem = e.srcElement || e.target;
if(elem.nodeName.toLowerCase() ==='td'&&this.closConfig.on)removeClass(elem,'thover')
},
dragOrWidth : function(e){
var elem = e.srcElement || e.target,widthConfig=this.widthConfig;

//执行拖拽
if(elem.nodeName.toLowerCase()==='td'){
this.closConfig.td = elem.getAttribute('clos');
addListener(document,'mousemove',this.dragMove));
addListener(document,'mouseup',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,this.widthMove));
addListener(document,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(){
var closConfig = this.closConfig,rows = this.table.getElementsByTagName('tr'),td,n,o,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.td1+1===closConfig.totd1){
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();
var widthConfig = 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,left:left+"px"});
},
widthUp : function(){
this.line.style.display = "none";
var widthConfig = 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(){
function checkName(val){
if(val.replace(/^\s+$/g,'')==='') return '姓名输入不能为空';
if(val.replace(/^\s+|\s+$/,'').length>10) return '姓名长度不能大于10个字符';
if(!/^[\u4e00-\u9fa5a-z]+$/i.test(val)) return '姓名只能输入中文或者是字母';
return true;
};
function checkRemark(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 '备注只能输入中文数字下划线空格';
return true;
}
var set = [
{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,edit:{rule:checkRemark,message:''}}
];
new Table($("tab"),set);
}

已知BUG:

ie6下 中文自动换行

非ie下字母和数字也不自动换行确实让人恼火

chrome浏览器下点击运行好像问题很大 拿到本地测试会比较好

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...