首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Ajax动态表格2.0升级

Posted on 2007-05-28 22:45  小城  阅读(821)  评论(1)    收藏  举报
/*--------------------------------------------------------------*
 *  xcTable  version 2.0  2007/05/21  by stenly
 *  说明: 实面多table同进绑定多xml数据源
 *  修正: 当请求一次xml数据后,分页时不用重新请求,可以分批显示数据记录
 *        checkbox在翻页的时候都可以保留该值
 *  修正: 分页时,不能识别是那个Table的问题
 *    修正: 改进了解释表格时的效率
 *
/*--------------------------------------------------------------
*/

/**
 * 把xml数据填充到表格的类 version 2.0
 * write by stenly 2007/05/21
 *
 
*/

XMLTable 
= Class.create();

XMLTable.prototype 
= {
  initialize: 
function(tabID_,xmlSource_) {
    
this.tabID           = tabID_;                    //被填充表格的ID号
    this.xmlSource       = xmlSource_;                //xml数据源,可以是jsp或asp文件

    
this.cloneRowIdx     = -1;                          //模版行的当前rowIndex,动态增加的
    this.factTabRowCount = 0;                          //实际行数
    this.xmlRecordCount  = 0;
    
this.xmlDoc          = null;
    
this.elAry;                                       //模版行的所有#{}内的元素名称,重复的去掉
    this.rowIdx          = -1;
    
this.colCount        = 0;                          //模版行的单元格数目
    this.tmplRowStr;                                  //模版行的innerHTML String
    this.tabObj;
    
this.tabRowCount;                                 //table的所有行数,包括非记录的行数
    this.cloneRowIdx;
    
this.factRecRowCnt;                               //实际输出的行数
  },
  fillTable:
function(startRow,recCntEachPage){
    startRow
--;   //下标从零开始
    this.reloadTable(this.tabObj);
    
if(this.xmlDoc != null){
      doXmlFill(
this,startRow,recCntEachPage);
    }
else{
      
this.init();
      
//传入一个this引用,在AjaxRequest类内把值设到外部的this.xmlDoc中,不然xmlDoc是传不出来的
      var oAjax = new AjaxRequest(this.xmlSource,this);
      oAjax.onSuccess 
= function(parent,xmlDoc){
        parent.xmlDoc 
= xmlDoc;   //直接用this.xmlDoc=xmlDoc无效
        doXmlFill(parent,startRow,recCntEachPage);
      }
      oAjax.onFailure 
= function(errorCode){
        alert(
"远程调用失败,错误代码: " + errorCode);
      }
      oAjax.doRequest();

    }

    
//private function define
    //parent为 XMLTable对象的引用
    function doXmlFill(parent,startRow,rowCntEachPage){
      parent.xmlRecordCount 
= parent.xmlRecordCount==0?parent.xmlDoc.getElementsByTagName("rec").length : parent.xmlRecordCount;
      
for(var tabRow=0; tabRow<rowCntEachPage && (tabRow + startRow)<parent.xmlRecordCount; tabRow++){
        
//copy模版行来处理
        var newRowClone = parent.tabObj.rows[parent.cloneRowIdx++].cloneNode(true);
        
//给该模版行填充数据
        newRowClone = xmlFillToRow(parent.xmlDoc,newRowClone,parent.colCount,parent.elAry,tabRow + startRow);
        
//总加在模版行的上一行
        parent.tabObj.rows[parent.rowIdx - 1].appendChild(newRowClone);
        
//取得实际行数
        parent.factRecRowCnt = tabRow + 1;
      }
      
//隐藏模版行
      //tabObj.deleteRow(_cloneRowIdx);
      parent.tabObj.rows[parent.cloneRowIdx].style.display ='none';

      
//private function define
      function xmlFillToRow(xmlDoc,newRowClone,colCount,elAry,xmlRow){
        
var tmplRowStr;                   //模版列的innerHTML
        var chkPosEachRow;                //记录每行checkbox的位置,事件绑定时不用重头历遍
        for(var j=0; j<colCount; j++){
          
///////////////////////////////////////////////////////////////
          //反回该行的所有TD单元格
          oNodes = newRowClone.childNodes[j].childNodes;
          
//处理每个单元格内所有的checkbox
          chkPosEachRow = fillCheckBox(oNodes,xmlDoc.getElementsByTagName("check")[xmlRow].text,xmlRow);
          
//////////////////////////////////////////////////////////////

          
//取出一个单元格的innerHTML
          oCellStr = newRowClone.childNodes[j].innerHTML;
          
//替换该列的所有#{}值
          for(var i=0; i<elAry.length; i++){
            oCellStr 
= parent.replaceStr(oCellStr,"#{" + elAry[i] + "}",xmlDoc.getElementsByTagName(elAry[i])[xmlRow].text);
          }

          
//处理后的每个单元格的innerHTML写回模版行
          newRowClone.childNodes[j].innerHTML = oCellStr;

          
//给该单元格的所有checkbox绑定事件处理函数
          bindEvent(xmlDoc,chkPosEachRow,newRowClone.childNodes[j]);
        }
        
return newRowClone;
      }

      
//处理checkBox的勾选显示
      function fillCheckBox(oNodes,isCheck,xmlRow){
        
var chkPosEachRow = new Array();      //记录每行checkbox的位置,事件绑定时不用重头历遍
        var j=0;
        
//历遍每个TD的子节点,如果是checkbox就判断是否要勾选
        for(var i=0; i<oNodes.length; i++){
          
var oNode = oNodes[i];
          
if(oNode.nodeName == "INPUT" && oNode.type == "checkbox"){
            
//checkbox的value记录xmlData记录集当前行的序列
            oNode.value = xmlRow;
            
//判断是否勾选
            oNode.checked = isCheck == "1"?true:false;
            chkPosEachRow[j
++= i;
            
//事件绑定放到这里没有效
            //eval("oNode.attachEvent('onclick',function() {updateXMLData(" + oNode.value + ")})");
          }
        }
        
return chkPosEachRow;
      }

      
//给每个checkbox绑定事件
      function bindEvent(xmlDoc,chkPosAry,oCell){
        
var oNode;
        
var oNodes = oCell.childNodes;
        
for(var i=0; i<chkPosAry.length; i++){
          oNode 
= oNodes[chkPosAry[i]];
          eval(
"oNode.attachEvent('onclick',function() {updateXMLData(xmlDoc,oNode)})");
        }

        
//历遍表格的每个子节点,这种算法的效率不够高
        /*
        var tab = document.getElementById(tabID);
        //已知模版列中定义了checkbox那么生成的各条记录都有checkbox,只需找出第一行的checkbox
        //位置即可,不用每一行都从头找出checkbox节省历遍时间
        //
        //历遍该表格的每一行
        for(var i = 0; i<tab.rows.length; i++){
          var oRow = tab.rows[i];       //取出行对象
          oCells = oRow.cells;          //每行有多少个单元格
          //历遍每行的所有单元格
          for(var j = 0; j<oCells.length; j++){
            var oCell = oCells[j];      //每行的一个单元格对象
            oNodes = oCell.childNodes;  //取出每个单元格的所有节点对象
            //历遍所有节点对象
            for(z = 0; z<oNodes.length; z++){
              var oNode = oNodes[z];
              if(oNode.nodeName == "INPUT" && oNode.type == "checkbox"){
                //eval("oNode.attachEvent('onclick',function() {updateXMLData(" + oNode.value + ")})");
                //eval("obj[i].attachEvent('onclick',function() {updateXMLData(obj[" + i + "])})");
              }
            }
         }
*/
        }

      
//同步更新xml文件
      function updateXMLData(xmlDoc,oChk){
        
//alert("xmlDate row=" + oChk.value);
        //alert(oChk.checked);
        xmlDoc.getElementsByTagName("check")[oChk.value].text = oChk.checked?1:0;
        
//alert(xmlDoc.getElementsByTagName("check")[oChk.value].text);
      }
    }
  },

  init:
function(){
      
this.tabObj = document.getElementById(this.tabID);
      
this.tabRowCount = this.tabObj.rows.length;

      
//寻找#{}所在的行
      for(var i = 0; i<this.tabRowCount; i++){
        
var oRow = this.tabObj.rows[i];
        
var rowStr = oRow.innerHTML;
        
if(rowStr.indexOf("#{")!=-1){
          
this.tmplRowStr = this.tabObj.rows[i].innerHTML;
          
//求模版行的单元格数目
          this.colCount = this.tabObj.rows[i].cells.length;
          
this.cloneRowIdx = i;
          
this.rowIdx = i;
          
break;
        }
      }
      
this.elAry = this.getElementName(this.tmplRowStr);
  },

  
//把所有#{}内的变量标识名放到数组中,重复的去掉
  getElementName:function(rowStr){
    
var i = 0;
    
var j;
    
var elStr;
    
var elAry = new Array();
    
var mark = true;
    
while(i > -1){
      i 
= rowStr.indexOf("#{",i + 1);
      j 
= rowStr.indexOf("}",j + 1);
      elStr 
= rowStr.substr(i + 2,j - i - 2);
      
if(elStr!=""){
        
for(var z=0; z<elAry.length; z++){
          
if(elStr == elAry[z]){
            mark 
= false;
            
break;
          }
        }
        
if(mark)
          elAry.push(elStr);
        mark 
= true;
      }
    }
    
return elAry;
  },



  replaceStr:
function(source,subjectStr,targetStr){
    
while(source.indexOf(subjectStr) != -1){
      source 
= source.replace(subjectStr,targetStr);
    }
    
return source;
  },

  
//复原到添加数据前的状态
  reloadTable:function(tabObj){
    
if(this.cloneRowIdx != -1){
      
for(var i=0; i<this.factRecRowCnt ; i++){
        tabObj.deleteRow(
this.cloneRowIdx - 1);
        
this.cloneRowIdx--;
      }
      tabObj.rows[
this.cloneRowIdx].style.display ='block';
    }
  },

  
//缺点,要一先执行上面的doRequest()才有值
  getRecordCount:function(){
    
return this.xmlRecordCount;
  }
}



/**
 * 控制表格分页的类
 * write by stenly 2007/05/12
 *
 
*/
//写类的构造函数
/*

var Class = {
    create: function() {
        return function() {
            this.initialize.apply(this, arguments);
        }
    }
}
*/
PageManage 
= Class.create();

PageManage.prototype 
= {

    initialize: 
function(xtObj,recCntEachPage) {
        
this.xtObj = xtObj;
        
this.tabID = xtObj.tabID;
        
this.actionSource = xtObj.xmlSource;
        
this.recCntEachPage = recCntEachPage;
        
this.curentPage = 1;
        
this.recordCount;
    },

    firstPage : 
function(){
        
this.curentPage = 1;
    
this.xtObj.fillTable(1,this.recCntEachPage);
    },

    prePage : 
function(){
        
if((this.curentPage - 1< 1return;
        
this.curentPage--;
        
var startRow = (this.curentPage - 1)*this.recCntEachPage + 1;
    
this.xtObj.fillTable(startRow,this.recCntEachPage);
    },

    nextPage : 
function(){
    
this.recordCount = this.xtObj.getRecordCount();
    
if(this.curentPage + 1 > Math.ceil(this.recordCount/this.recCntEachPage,true)) return;
        
this.curentPage++;
        
var startRow = (this.curentPage - 1)*this.recCntEachPage + 1;
    
this.xtObj.fillTable(startRow,this.recCntEachPage);
    },

    lastPage : 
function(){
    
this.recordCount = this.xtObj.getRecordCount();
        
this.curentPage = Math.ceil(this.recordCount/this.recCntEachPage);
        
var startRow = (Math.ceil(this.recordCount/this.recCntEachPage) - 1)*this.recCntEachPage + 1;
    
this.xtObj.fillTable(startRow,this.recCntEachPage);
    },

    update : 
function(me){
        
this.recCntEachPage = me.value;
        
this.firstPage();
    }
}
调用:
<span style="cursor:hand" onclick="tab2_pm.firstPage();">|<</span>&nbsp;
    
<span style="cursor:hand" onclick="tab2_pm.prePage();"><<</span>&nbsp;
    
<span style="cursor:hand" onclick="tab2_pm.nextPage();">>></span>&nbsp;
    
<span style="cursor:hand" onclick="tab2_pm.lastPage();">>|</span>&nbsp;
    
<input type="text" id="tab2_recCntEachPage" value="3" onchange="tab2_pm.update(this)">
    
<script>

      
var tab2_xtObj = new XMLTable("tab2","data.xml");
           
      
var tab2_recCntEachPage = document.getElementById("tab2_recCntEachPage").value;

      tab2_xtObj.fillTable(
1,tab2_recCntEachPage);

      tab2_pm 
= new PageManage(tab2_xtObj,tab2_recCntEachPage);

    
</script>
用标签封装了的写法
<pageManage:navigator tableID="tab1" xmlsrc="data.xml" recordCount=3/>