首页 > web前端 > js教程 > 正文

原生javascript实现简单的datagrid数据表格_javascript技巧

WBOY
发布: 2016-05-16 16:22:34
原创
1418 人浏览过

简单的datagrid

1.排序 自定义排序方式

2.编辑

3.拖拽

4.分页

5.单选 多选(ctrl) 线性选(shift)

6.文字render  就是给文字着色  比如 大于0红色  小于0绿色

7.对列的显示隐藏

8.分组

只是一个示例  没有什么与后台的借口

其实可以写几个回调就行了  里面有loading条 可以在没返回结果前一直显示

复制代码 代码如下:

 
http://www.w3.org/1999/xhtml">


table



1.排序 自定义排序方式


2.编辑


3.拖拽


4.分页


5.单选 多选(ctrl) 线性选(shift)


6.文字render  就是给文字着色  比如 大于0红色  小于0绿色


7.对列的显示隐藏


8.分组





下面是分组的  且有一个自定义排序方式  很好 一般 很差



跳转删除
当前第页 总共页 一页条数据 共条数据
';
   var tabContainer = this.tabContainer  = $c('div',container);
   this.bottom = $c(this.top.cloneNode(true),container);
   tabContainer.className = 'tabcontainer';
   tabContainer.style.height =  ~~options.container.offsetHeight - 83+'px';
   var table = this.table = $c('table',tabContainer);
   table.className = 't_a';
   setAttr(table,{cellpadding :"0",cellspacing:"0",border :"0"});
   this.thead = $c('thead',table);
   this.tbody = $c('tbody',table);
   this.tbody.style.display = 'none';
   //loading条 
   this.loading_bg = $c('div',container);
   this.loading_bg.className = 'loading';
   setStyle(this.loading_bg,{
    width  : container.offsetWidth+2+'px',
    height : container.offsetHeight+2+'px'
   });
   
   this.loading = $c('div',container);
   this.loading.className ='loaddiv'
   setStyle(this.loading,{
    left:(container.offsetWidth/2-45) + 'px',
    top:(container.offsetHeight/2-14) + 'px'
   });
   this.loading.innerHTML = '
Loading...
';   
   
   //表格有多少列
   this.colCount = options.fields.length;
   // 数据源 形式是 [[],[],[],[],[],[]]
   this.data  = [];
   // 当前请求到的数据源中  所有的分组头 形式是 [trdom1,trdom2]
   this.grouphead  = [];   
   //记录已经插入table的分组的tr      [tr1,tr2,tr3]
   this.insertTrs = [];
   //列索引
   //形式 [[td11,td12,td13,td14],[td21,td22,td23,td24]]
   this.columns = [];
       
   //true表示正序 false表示反序
   this.ascSort = true;   
   
   //保存哪一列正在排序中的表头td 
   this.sortColumn = '';
   
   //所有tr行  如果没有分组 形式是[tr1,tr2,tr3,tr4]
   //如果有分组  [[tr1,tr2,tr3,tr4],[tr5,tr6,tr7,tr8]]
   this.rows =[];
  
   //一级菜单
   this.popMenu = $c('div',doc.body);
   this.popMenu.className = 'x-menu';
   this.popMenu.innerHTML = '';
   
   // 创建子菜单 
   this.subPopMenu = $c('div',doc.body);
   this.subPopMenu.className = 'submenu';
   
   //表头的第一级弹出层是否打开 如果打开  保存 该td
   this.isMenuOpen = false;
   
   //保存列所有列中 某一列是否显示 或隐藏 num为计数器 看有多少列是现实中的
   //格式   clos: [ true,false,true,true] 1,3,4列显示  第2列隐藏
   this.isShowTrs = {
    num : 0,
    clos: []
   };
   
   // 创建拖动时显示的基准线
   this.line = $c('div',doc.body);
   this.line.className = 'line';
   
   //保存行
   //属性为uuid的递增量如 {1:dom,2:dom}
   this.selectedRows = {};
   
   // 保存最后选中的行
   this.lastSelectRow = {dom:null,index:null};
   
   this.currentEditRow = {index:0,dom:null};
   this.editData = [];
   this.editForm = $c('div',tabContainer);;
   setStyle(this.editForm,{
    position : 'absolute',
    display  : 'none',
    'z-index': '120'
   });
   this.editTable = $c('table',this.editForm);
   setAttr(this.editTable,{
    cellspacing:'0',
    cellpadding:'0',
    border:'0'
   });
   var btnC = $c('div',this.editForm);
   btnC.className = 'editbtn';
   btnC.style.textAlign = 'center';
   btnC.innerHTML = '';
   this.editTable.className = 'edittable';
   var etr = $c('tr', $c('tbody',this.editTable));
      
   //创建一个 tr 的副本  因为后面生成tr的时候 可以直接复制节点
   this.copyTr  = $c('tr');
   this.groupTr = $c('tr');
   this.groupTr.setAttribute('g','y');
   var ctd= $c('td',this.groupTr)
   ctd.setAttribute('colSpan',options.fields.length);
 
   var theadTr = $c('tr',this.thead),
    tWidth  = 0,
    self    = this,
    ul      = $c('ul',this.subPopMenu),
    li;
   each(options.fields,function(i,o){
    var td = $c('td',theadTr),
     width = o.width?o.width:'80',
     div = i===0?'
':'

';
    td.innerHTML = [div,'',o.name,'
'].join('');
    setAttr(td,{clos:i,width:width,unselectable:'on','class':o.type === undefined?'':'type-'+o.type});
    self.createInput(i,o,etr);
    tWidth = tWidth + (~~width);   
    li = $c('li',ul);
    li.innerHTML = [
     '',
     o.name,
     '
'
    ].join('');
    
    //生成列索引 的  每列的第一项
    self.columns[i] = [td];
    $c('td',self.copyTr).setAttribute('unselectable','on');
    //计算出 所显示的列索引 和 一共多少列num      
    self.isShowTrs.num++;
    self.isShowTrs.clos[i]=true;    
   });
   
   setAttr(this.table,{width:tWidth+options.fields.length+1})
   
   //生成tbody里面的tr 只是生成 tr 根据perPage生成 它是显示当前一共有多少条数据的配置项
   var i=0,
    trsLen = options.perPage,
    frag   = doc.createDocumentFragment(),
    arr    = new Array(options.fields.length),
    tr,
    tds;
   for(;i     tr  = this.copyTr.cloneNode(true);
    tds = $q('td',tr);
    each(arr,function(i){
     //生成列索引的所有项
     self.columns[i].push(tds[i]);
    });
    $c(tr,frag);
   }
   this.tbody.appendChild(frag);
   if(typeof dataConfig === 'object'){
    setTimeout(function(){self.getDataCallBack(dataConfig);},5);    
   }else{
    
   }
   /*
    表格拖拽
    表格排序
    等一些操作
   */
   addListener(this.thead,'click',bindAsEventListener(this,this.sortTable));
   addListener(this.thead,'mouseover',bindAsEventListener(this,this.theadOver));
   addListener(this.thead,'mouseout',bindAsEventListener(this,this.theadOut));
   addListener(this.thead,'mousedown',bindAsEventListener(this,this.dragWidth));
   
   /*
    绑定弹出层click事件  进行排序
    第2级菜单绑定  进行对列隐藏 显示
   */
   addListener(this.popMenu,'click',bindAsEventListener(this,this.menuClick));
   addListener(this.popMenu,'mouseover',bindAsEventListener(this,this.menuOver));
   addListener(this.subPopMenu,'click',bindAsEventListener(this,this.subMenuClick));
   
   /*
    放上去表格行的内容变粗
   */
   addListener(this.tbody,'mousemove',bindAsEventListener(this,this.rowHighlight,true));
   addListener(this.tbody,'mouseout',bindAsEventListener(this,this.rowHighlight,false));
   addListener(this.tbody,'mousedown',bindAsEventListener(this,this.selectRow,false));
   addListener(this.tbody,'dblclick',bindAsEventListener(this,this.editRow,false));
   
   addListener(btnC,'click',bindAsEventListener(this,this.modifyTr));
   
   addListener(this.top,'click',bindAsEventListener(this,this.pageBarClick));
   addListener(this.bottom,'click',bindAsEventListener(this,this.pageBarClick));
  },
  getDataCallBack : function(data){
   var options = this.defaults,
    self    = this,
    totla   = 0;
   
   this.data.length = 0;
   
   if(data.data){
    if(data.data[0].groupName){
     var grouphead = this.grouphead;
     grouphead.length = 0;
     
     each(data.data,function(i,o){
      var gtr = self.groupTr.cloneNode(true);
      $q('td',gtr)[0].innerHTML = o.groupName;
      grouphead.push(gtr);
      each(o.rows,function(j,d){
      //this.data中数据的最后一项是 索引
       d.push(i);            
       self.data.push(d);    
      });      
     });
     this.showGroup=true;
    }else{
     each(data.data,function(i,o){          
      self.data.push(o);     
     });
     this.showGroup=false;
    }
   }else{
    return;
   }
   total = data.total
     ? data.total>=this.data.length
      ? data.total
      : this.data.length
     : this.data.length;
   this.writeMessage(total);
   this.buildTbody(options.currPage);
  },  
  buildTbody : function(pageNum){
   if(this.data.length===0){
    this.tbody.style.display = 'none';
    return; 
   }
   
   var i       = 0,
    j       = 0,
    self    = this,
    data    = this.data,
    options = this.defaults,
    trsLen  = options.perPage,
    tdsLen  = options.fields.length,
    tbody   = this.tbody,
    trs     = tbody.getElementsByTagName('tr'),
    start   = pageNum*options.perPage,
    tr;
   this.rows.length = 0;
   
   if(this.showGroup){
    var group = {},
     index,
     arr = [],
     insertTrs = this.insertTrs;
           
    //清除掉之前插入的 分组tr
    insertTrs.length!=0&&each(insertTrs,function(i,o){
     self.tbody.removeChild(o);
    });
    insertTrs.length = 0;     
    
    //遍历填充数据 给this.rows赋值    
    var num = - 1;
    for(;i      tr = trs[i];
     
     //如果没有数据了  就开始隐藏剩下的行
     if(!data[i+start]){
      tr.style.display = 'none';
      continue;
     }
     
     //做标记 tr 里面的内容对应data中哪条数据 
     tr.setAttribute('dataIndex',i+start);
     tr.style.display = 'block';
     tds = tr.getElementsByTagName('td');
     //x为 分组的不同组的标识
     var x = data[i+start][data[i+start].length-1];
     //用来判断后来的数据和之前的数据是不是同一个组的
     //如果是同一个组的 选this.rows的最后一列添加
     //不是同一个组的创建一列添加
 
     num==x
      ? this.rows[this.rows.length-1].push(tr)
      : (this.rows[this.rows.length] = [tr],num = x);
      
     //用数组arr 记住每个分组的的第一个tr的位置 因为后面要插入tr头  i为位置 num为分组的序号  
     !(num in group)&&(group[num] = i + start,arr.push([num,i]));
     for(j = 0;j       td = tds[j];
      var txt   = data[i+start][j] ===''?' ':data[i+start][j];
       render = options.fields[j].render;
       td.innerHTML = render
        ?render(txt)
        :txt;     
     }
     tr.style.display = '';            
    }
 
    each(arr.reverse(),function(i,o){
     insertTrs.push(self.grouphead[o[0]]);
     self.tbody.insertBefore(self.grouphead[o[0]],trs[o[1]]); 
    });     
 
   }else{
    for(;i      tr = trs[i];
     //做标记 tr 里面的内容对应data中哪条数据 
     tr.setAttribute('dataIndex',i+start);     
     this.rows.push(tr);
     //没有数据的tr隐藏掉
     if(!data[i+start]){
      tr.style.display = 'none';
      continue;
     }
     tr.style.display = '';
     tds = $q('td',tr);
  
     for(j = 0;j       var txt   = data[i+start][j] ===''?' ':data[i+start][j];
       render = options.fields[j].render;
       tds[j].innerHTML = render
        ?render(txt)
        :txt;            
     }
    }   
   }
   
   options.currPage = pageNum;
   this.top.getElementsByTagName('span')[0].innerHTML=this.bottom.getElementsByTagName('span')[0].innerHTML = ~~pageNum+1; 
   var topAs = this.top.getElementsByTagName('a'),
    bottomAs = this.bottom.getElementsByTagName('a');
   if(options.totalPage===1){
    bottomAs[0].className = topAs[0].className = 'first_div_no';
    bottomAs[1].className = topAs[1].className = 'prev_div_no';
    bottomAs[2].className = topAs[2].className = 'next_div_no';
    bottomAs[3].className = topAs[3].className = 'last_div_no';
   }else if(options.currPage===0){
    bottomAs[0].className = topAs[0].className = 'first_div_no';
    bottomAs[1].className = topAs[1].className = 'prev_div_no';
    bottomAs[2].className = topAs[2].className = 'next_div';
    bottomAs[3].className = topAs[3].className = 'last_div'; 
   }else if(options.currPage+1===options.totalPage){
    bottomAs[0].className = topAs[0].className = 'first_div';
    bottomAs[1].className = topAs[1].className = 'prev_div';
    bottomAs[2].className = topAs[2].className = 'next_div_no';
    bottomAs[3].className = topAs[3].className = 'last_div_no';
   }else{
    bottomAs[0].className = topAs[0].className = 'first_div';
    bottomAs[1].className = topAs[1].className = 'prev_div';
    bottomAs[2].className = topAs[2].className = 'next_div';
    bottomAs[3].className = topAs[3].className = 'last_div';
   }
   
   this.tbody.style.display = '';
   this.loading_bg.style.display ='none';
   this.loading.style.display ='none';
   
  },
  writeMessage : function(total){
   var options     = this.defaults,
    base        = total/options.perPage,
    topSpans    = this.top.getElementsByTagName('span'),
    bottomSpans = this.bottom.getElementsByTagName('span');    
   options.totalPage = base > parseInt(base)
         ? parseInt(base)+1
         : base; 
   bottomSpans[0].innerHTML = topSpans[0].innerHTML = ~~options.currPage+1;
   bottomSpans[1].innerHTML = topSpans[1].innerHTML = options.totalPage;
   bottomSpans[2].innerHTML = topSpans[2].innerHTML = options.perPage;
   bottomSpans[3].innerHTML = topSpans[3].innerHTML = total;
  },  
  sortTable : function(e){
   var elem = e.target || e.srcElement,    
    self = this,
    options   = this.defaults,
    elemName  = elem.nodeName.toLowerCase(),
    showGroup = this.showGroup,
    tdElem    = elem,
    name      = elemName;
    
   //拖拽的时候可能会触发一次click 原因是ie下全部绑定在this.table上 代码见拖拽
   if($q('td',elem).length>1)
    return;
   if(name !== 'td'){
    while(name !== 'td'){
     tdElem = tdElem.parentNode;
     name = tdElem.nodeName.toLowerCase();
    } 
   }
   var issort = checkReg(tdElem.className,'sort'),
    type   = checkReg(tdElem.className,'type')
   
   //进行排序
   if(elemName !=='a'&&type){
    
    var frag = doc.createDocumentFragment();
    if(this.sortColumn!==tdElem&&this.sortColumn!==''){
     removeClass(this.sortColumn,'sort-asc');
     removeClass(this.sortColumn,'sort-desc');
    } 
    if(issort){
     // 有分组,每组单独取反序  不分组,直接取反序
     showGroup
      ? each(this.rows,function(i,o){ o.reverse();}) 
      : this.rows.reverse();
      tdElem.className = modify(tdElem.className,'sort',issort==='asc'?'desc':'asc');
    }else{
     showGroup
      ? each(this.rows,function(i,o){
       o.sort(self.compare(tdElem.getAttribute('clos'),type));
      })
      : this.rows.sort(this.compare(tdElem.getAttribute('clos'),type));
     
     // 如果是正序排序,加上正序排列的标志。 
     if(this.ascSort){        
      addClass(tdElem,'sort-asc');
     }else{
      // 反序排列则将原有排序取反,并加上排序标志
      showGroup
       ? each(this.rows,function(i,o){ o.reverse();})
       : this.rows.reverse();
      addClass(tdElem,'sort-desc');
     }    
    }
    
    // 将排序后的数据渲染到表格
    var insertTrs = this.insertTrs,
     len = insertTrs.length-1,
     arr = [];    
    
    each(this.rows,function(i,tr){
     arr = [insertTrs[len-i]].concat(tr);
     showGroup       
      ? each(arr,function(idx,obj){frag.appendChild(obj);})
      : frag.appendChild(tr);     
    });
    this.tbody.appendChild(frag);
    this.sortColumn = tdElem;
   }
   
   //-------------------------------------------------------------------------------------
   /*
   如果点击的是表头中的 A 标签,则弹出菜单     
   */
   if(elemName === 'a'){
    /*
     当在菜单外面点击的时候会执行 改函数
     用于清空 document的 click事件   隐藏层 去掉td,a的样式            
    */ 
    function documentClick(){
     self.popMenu.style.display = 'none';
     self.subPopMenu.style.display = 'none';
     if(self.isMenuOpen){
      removeListener(document,'click');
      removeClass($q('div',self.isMenuOpen)[0],'theadfocus');
      $q('a',self.isMenuOpen)[0].style.display = 'none';
     } 
     self.isMenuOpen = false;
    }
     
    var pos  = objPos(elem),
     left = pos.left+Math.max(document.documentElement.scrollLeft,document.documentElement.scrollLeft),
     top  = pos.top +Math.max(document.documentElement.scrollTop,document.documentElement.scrollTop)+ elem.offsetHeight,
     td   = elem.parentNode.parentNode,
     lis  = $q('li',this.popMenu);
      
    //如果this.isMenuOpen是真 表示 层是打开状态的  执行关闭相关的处理
    this.isMenuOpen&&documentClick();
    
    if(!checkReg(td.className,'type')){
     addClass(lis[0],'disabled');
     addClass(lis[1],'disabled');
    }else{
     removeClass(lis[0],'disabled');
     removeClass(lis[1],'disabled');
    }
    Sys.ie
     ? e.cancelBubble = true
     : e.stopPropagation();
    //当显示层的时候 吧该td附到this.isMenuOpen上
    this.isMenuOpen = td;     
    addListener(document,'click',documentClick);
    setStyle(this.popMenu,{
     left    : left+'px',
     top     : top+'px',
     display :'block' 
    });   
   }
  },
  compare : function(n,type){
   var sortType = this.defaults.sortType,
    txt =Sys.ie?'innerText':'textContent';
   !sortType[type]&&(type = 'string');
   return function(a1,a2){
    a1 = sortType[type](a1.cells[n][txt]);
    a2 = sortType[type](a2.cells[n][txt]);
    return a1==a2?0:a1    }
  },   
  pageBarClick : function(e){
   var elem     = e.target || e.srcElement,
    options  = this.defaults,
    typePage = elem.getAttribute('page'),
    isGo     = elem.getAttribute('go');
    isDel    = elem.getAttribute('del');
    
    if(typePage){
     var number = {
      start : 0,
      end   : options.totalPage-1,
      next  : options.currPage-1,
      pre   : options.currPage+1
     }[typePage];
     this.toPage(number);
    }
    if(isDel){
     this.del();
    }
    
    if(isGo){
     var number = ~~elem.parentNode.getElementsByTagName('input')[0].value-1;
     this.toPage(number);
    }  
  },
  toPage : function(num){
   if(typeof num !=='number'||isNaN(num))return;
   var options    = this.defaults,
    self       = this,
    dataConfig = options.dataConfig;    
   //如果请求的分页数小于0就默认为0  如果打越最大分页数 就默认为最大分页数
   num>=options.totalPage
    &&(num = options.totalPage-1);
   num    
   //s为当前面板的第一页  e为当前面板的最后
   var basePage = options.count/options.perPage,
    s = options.page*basePage,
    e = s + basePage-1;
   this.tbody.style.display = 'none';
   this.loading_bg.style.display = '';;
   this.loading.style.display = '';
   setTimeout(function(){self.buildTbody(num);},10);  
   
  },
  del : function(){
   //做删除的时候需要有主键的索引  我全部保存在tr的
   var selectedRows = this.selectedRows,
    arr = []
    for(var name in selectedRows){     
     arr.push(selectedRows[name].getAttribute('dataIndex'));
    }
   alert('选择了主键值为'+arr.join(','));
  },
  theadOver : function(e){
   var elem = e.target || e.srcElement;
   if(elem.nodeName.toLowerCase() === 'div'){
    $q('a',elem)[0].style.display = 'block';
    addClass(elem,'theadfocus');
   }
  },
  theadOut : function(e){
   var elem     = e.target || e.srcElement,
    toElem   = e.toElement||e.relatedTarget,
    elemName = elem.nodeName.toLowerCase();
   
   if(this.isMenuOpen && contains(this.isMenuOpen,elem))
    return;
   
   //如果离开了当前的td 隐藏显示出来的东西
   if(elemName === 'div'&& elem !== this.isMenuOpen){   
    if(!contains(elem,toElem)){
     $q('a',elem)[0].style.display = 'none';
     removeClass(elem,'theadfocus');
    }
   }
 
   if(elemName === 'a' || elemName ==='span' || elemName === 'p'){
    var  parent = elem.parentNode;
    if(!contains(elem,toElem)){
     $q('a',parent)[0].style.display = 'none';
     removeClass(parent,'theadfocus');
    }
   }
  },
  menuClick : function(e){
   var elem       = e.target || e.srcElement,
    className  = this.isMenuOpen.className;
   if(elem.nodeName.toLowerCase()==='a'){
    //如果td的样式中不存在type 也就是说不需要排序 则不进行排序 阻止事件冒泡
    if(!checkReg(className,'type')){
     Sys.ie
      ? e.cancelBubble = true
      : e.stopPropagation();
     return;
    }
     
    //如果a标签 的menuType        
相关标签:
来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!