表格的自定義排序 編輯 拖拽 縮放

終於能閒下來做點自己想做的事情了..

 簡單表格排序 

 可以雙擊編輯 自定義編輯後的 規則

 可拖動列進行列替換

 可推動邊框進行列寬度的縮放 

 ie6下 中文不自動換行

 非ie下字母和數字也不自動換行確實讓人惱火

 chrome瀏覽器下點擊運行好像問題很大  拿到本地測試會比較好

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>Table</title>
</head>
<style type="text/css">
body{ font-size:12px}
#tab{ border-collapse: collapse;}
.edit{ height:16px; width:98%; background-color:#EFF7FF; font-size:12px; border:0px;}
#tab thead td{ background:url(http://images.cnblogs.com/cnblogs_com/wtcsy/192373/r_t.bmp);color:#183C94;word-break:break-all}
#tab tbody td{overflow:hidden;word-break:break-all;}
#tab td{border: 1px solid #CECFCE;height:20px;line-height:20px;vertical-align:middle; }
#tab td.tc{text-align:center;}
.div{width:10px;height:6px; border:1px solid #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;}
#tab thead td.thover{ background-image:url(http://album.hi.csdn.net/app_uploads/wtcsy/20081126/000054336.p.gif);background-repeat:repeat-x;}
</style>
<body >
<table id="tab"  border="0" cellspacing="1" cellpadding="0">
 <thead>
   <tr>
       <td width="80"class="tc" ><span class="l">ID</span><div class="r dr"></div></td>
       <td width="80"class="tc"><span class="l">選中</span><div class="r dr"></div></td>
       <td  width="130" class="tc"><span class="l">姓名</span><div class="r dr"></div></td>
       <td width="130" class="tc" ><span class="l">生日</span><div class="r dr"></div></td>
       <td width="220" class="tc" ><span class="l">備註</span><div class="r dr"></div></td>
   </tr>
  </thead>
  <tbody>
  <tr>
    <td height="16">1</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>小三</td>
    <td>1982-05-27</td>
    <td>杯具,全是杯具</td>
  </tr>
  <tr>
    <td>3</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>李四</td>
    <td>1983-06-27</td>
    <td>恩恩我魔獸技術不錯</td>    
  </tr>
  <tr>
    <td>2</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>王五</td>
    <td>1987-05-27</td>
    <td>波斯王子 時之刃還不錯</td>    
  </tr>
  <tr>
    <td>4</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>趙六</td>
    <td>1988-05-27</td>
    <td>我叫趙六</td>    
  </tr>
  <tr>
    <td>5</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>朱八</td>
    <td>1984-05-27</td>
    <td>洗洗睡吧</td>    
  </tr>
  <tr>
    <td>6</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>阿斯多夫</td>
    <td>1984-06-27</td>
    <td>阿斯多夫暗室逢燈</td>    
  </tr>
  <tr>
    <td>7</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>杯具</td>
    <td>1984-06-27</td>
    <td>很多的杯具</td>    
  </tr>
  <tr>
    <td>8</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>餐具</td>
    <td>1984-02-27</td>
    <td>很多的餐具</td>    
  </tr>
  <tr>
    <td>8</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>洗具</td>
    <td>1984-08-27</td>
    <td>很多的洗具</td>    
  </tr> 
  <tr>
    <td>9</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>內牛滿面</td>
    <td>1984-12-27</td>
    <td>10快一晚</td>    
  </tr>
  <tr>
    <td>10</td>
    <td><input type ="checkbox"><input name="ss" type="radio"  /></td>
    <td>犀利哥</td>
    <td>1984-12-21</td>
    <td>嘿嘿</td>    
  </tr>                        
  </tbody>
</table>
<script language="javascript">
(function(window,undefined){
window.Sys = function (ua){
    var b = {
        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 (var i in b) {
        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;   
    return b;
}(window.navigator.userAgent.toLowerCase());

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,e,fn){
    var handlers = element.events[e],type;
    if(fn){
        for(type in handlers)
            if(handlers[type]===fn){
                element.removeEventListener?element.removeEventListener(e,fn,false):element.detachEvent("on" + e,fn);
                delete handlers[type];
            }
    }else{
        for(type in handlers){
            element.removeEventListener?element.removeEventListener(e,handlers[type],false):element.detachEvent("on" + e,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(;i<length;i++){
		if ( (options = arguments[ i ]) != null )
			for(var name in options){
				var src = target[ name ], copy = 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('(\\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(new RegExp('(\\s|^)'+className+'(\\s|$)'),' ')); 
} 
})(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(;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):(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<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.srcElement or e.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爲進行什麼類型的排序
        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 =convert[type](a1.cells[n].innerHTML);
			a2 =convert[type](a2.cells[n].innerHTML);
			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',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(){
        var closConfig = 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();
		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,{display:"block",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,type:"string",edit:{rule:checkRemark,message:''}}
    ];
    new Table($("tab"),set);
}
</script>
</body>
</html>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章