javascript实现动态模态绑定grid过程代码


Posted in Javascript onSeptember 22, 2014
<html> 
<head> 
  <style type="text/css"> 
    .grid{border:1px solid #808080; border-spacing:0; width:500px; border-collapse:collapse} 
    .grid th,.grid td{border:0; text-align:center;} 
    .grid tr{height:25px;line-height:25px;} 
    .grid tr.odd{background:#d0d0d0} 
    .grid .btn{width:80px; text-align:center}     
  </style> 
   
  <script type="text/javascript"> 
    (function(){ 
      // 
      var util = { 
        next:function next(ele){ 
          if(ele){ 
            var n = ele.nextSibling; 
            if(n && n.nodeType === 1){ 
              return n; 
            } 
            return next(n); 
          } 
        }, 
        parseJSON:function(str){ 
          if(typeof JSON !== "undefined"){ 
            return JSON.parse(str); 
          } 
          return eval("("+str+")"); 
        }, 
        parseArray:function(obj){ 
          if(!obj){ 
            return obj; 
          } 
          var result = []; 
          if(typeof obj.length !== "undefined"){ 
            try{ 
              var arr = Array.prototype.slice.call(obj,0); 
              result = arr; 
            }catch(e){ 
              for(var i=0;i<obj.length;i++){ 
                try{ 
                  var target = obj[i]; 
                }catch(e){ 
                  if(obj.item){ 
                    var target = this.item(i);//nodeList 
                  } 
                } 
                if(typeof target !== "undefined"){ 
                  result.push(target); 
                  delete target; 
                } 
              } 
            } 
          } 
          return result; 
        }, 
        isFunction:function(fn){ 
          return typeof fn === "function"; 
        }, 
        trim:function(str){ 
          if(typeof str !== "string"){ 
            return str; 
          } 
          return str.replace(/^\s+|\s+$/g,""); 
        }, 
        offset:function offset(ele){ 
          var result = {top:0,left:0}; 
          if(!ele || ele.nodeType !== 1){ 
            return result; 
          } 
          result.top = Number(ele.offsetTop || (ele.style.top || "0").replace(/[^\d]+$/,"")); 
          result.left = Number(ele.offsetLeft || (ele.style.left || "0").replace(/[^\d]+$/,"")); 
          if(ele.parentNode){ 
            var r = offset(ele.parentNode); 
            result.top += r.top; 
            result.left += r.left; 
          } 
          return result; 
        } 
      }; 
       
      //事件处理 
      var Event = { 
        on:function(eventType,fn){ 
          var element = this; 
          if(this.addEventListener){ 
            this.addEventListener(eventType,fn,false); 
          }else if(this.attachEvent){ 
             //将事件缓冲到该标签上,已解决this指向window(现fn内this指向element)和移除匿名事件问题             
            var _EventRef='_'+eventType+'EventRef'; 
            if(!element[_EventRef]){ 
              element[_EventRef]=[]; 
            } 
            var _EventRefs=element[_EventRef]; 
            var index; 
            for(index in _EventRefs){ 
              if(_EventRefs[index]['realFn']==fn){ 
                return; 
              } 
            } 
            var nestFn=function(){ 
              fn.apply(element,arguments); 
            }; 
            element[_EventRef].push({'realFn':fn,'nestFn':nestFn}); 
            element.attachEvent('on'+eventType,nestFn); 
          }           
        }, 
        remove:function(eventType,fn){      
          var element = this;    
          if(this.removeEventListener){ 
            this.removeEventListener(eventType,fn,false); 
          }else if(this.detachEvent){ 
            var _EventRef='_'+eventType+'EventRef'; 
            if(!element[_EventRef]){ 
              element[_EventRef]=[]; 
            } 
            var _EventRefs=element[_EventRef] 
            var index; 
            var nestFn; 
            for(index in _EventRefs){ 
              if(_EventRefs[index]['realFn']==fn){ 
                nestFn=_EventRefs[index]['nestFn']; 
                if(index==_EventRefs.length-1){ 
                  element[_EventRef]=_EventRefs.slice(0,index); 
                }else{ 
                  element[_EventRef]=_EventRefs.slice(0,index).concat(_EventRefs.slice(index+1,_EventRefs.length-1)); 
                } 
                break; 
              } 
            } 
            if(nestFn){ 
              element.detachEvent('on'+eventType,nestFn); 
            } 
          } 
        } 
      }; 
       
      //extend 
      (function(){ 
        //删除数组中指定下标出的元素 
        Array.prototype.remove = function(index){ 
          var o = this[index]; 
          if(typeof o !== "undefined"){ 
            if(index == 0){ 
              this.shift(); 
            }else if(index === this.length - 1){ 
              this.pop(); 
            }else{ 
              var arr1 = this.slice(0,index); 
              var arr2 = this.slice(index+1); 
              this.length = 0; 
              this.concat(arr1,arr2); 
            } 
          } 
        } 
        //删除数组中所有的元素 
        Array.prototype.clear = function(){ 
          this.length = 0; 
        } 
        //each 
        Array.prototype.each = function(fn){ 
          if(!util.isFunction(fn)){ 
            return; 
          } 
          for(var i=0;i<this.length;i++){ 
            if(typeof this[i] !== "undefined"){ 
              fn.call(this[i],i); 
            } 
          } 
        } 
         
        // 
        var collection = this.collection = function(){ 
          this.__data = {}; 
          this.length = 0; 
        } 
        collection.prototype = { 
          add:function(obj){ 
            this.__data[this.length++] = obj; 
          }, 
          get:function(index){ 
            return this.__data[index]; 
          }, 
          remove:function(index){ 
            var obj = this.__data[index]; 
            if(typeof obj !== "undefined"){ 
              this.length--; 
            } 
            delete this.__data[index]; 
          }, 
          clear:function(){ 
            this.__data = {}; 
            this.length = 0; 
          }, 
          each:function(fn){ 
            var index = 0; 
            for(var k in this.__data){ 
              if(k && typeof this.__data[k] !== "undefined"){ 
                fn.call(this.__data[k],index++); 
              } 
            } 
          }, 
          toArray:function(){ 
            var arr = []; 
            this.each(function(){ 
              arr.push(this); 
            }); 
            return arr; 
          } 
        }; 
      })(); 
      // 
      var grid = this.grid = function(table, options){ 
        grid.prototype._init.call(this,table,options); 
      } 
      grid.prototype = { 
        _init:function(table, options){ 
          if(typeof table === "undefined" || !table){ 
            throw "table is undefined or null"; 
          } 
          if(table.nodeType !== 1 || !/^table$/i.test(table.tagName)){ 
            throw "table must be 'table' element."; 
          } 
          table.guid = ++grid.guid; 
          this.__cache = {}; 
          var self = this; 
          var header = this.__cache["header"] = loadHeader();//header 
          this.__root = header.parentNode; 
          var templateRow = this.__cache["template"] = loadTemplate();//模板行 
          this.__cache["dataFormat"] = loadDataFormat();//数据模板 
          this.__cache["dataRows"] = new collection();//数据行 
          this.__cache["customCache"] = new collection();//用户缓存数据 
          this.__editRow = null;//当前编辑行 
          this.__saveContainer = createSaveButton();//保存按钮 
          this.__cache["commandHandles"] = {//command handels 
            removeRow:function(){ 
              var rowIndex = this.getAttribute("index"); 
              self.removeRow.apply(self,[rowIndex]); 
            }, 
            newLine:function(){ 
              self.newLine(); 
            } 
          }; 
          this.__regCommand = function(commandName,row){ //注册command 
            if(row){ 
              var arg = row.getAttribute("index"); 
              this.setAttribute("index",arg || false); 
            } 
            this.commandName = commandName; 
            Event.remove.call(this,"click",exec); 
            Event.on.call(this,"click",exec); 
          } 
          this.__removeRowCallback = function(){ //改变行的背景样式 
            var rows = this.__cache["dataRows"]; 
            var customCache = this.__cache["customCache"]; 
            var arr = rows.toArray(),dataArr=[]; 
            var rowIndex,row,data; 
             
            rows.clear(); 
            arr.each(function(i){ 
              rowIndex = this.getAttribute("index"); 
              data = customCache.get(rowIndex); 
              dataArr.push(data); 
              this.setAttribute("index",i.toString()); 
              rows.add(this); 
              if( i % 2 == 1){//基数行 
                if(!/\sodd\s|\sodd$/g.test(this.className)){ 
                  this.className = (this.className || "") + " odd"; 
                } 
              }else if(/\sodd\s|\sodd$/g.test(this.className)){ 
                this.className = this.className.replace(/\sodd\s|\sodd$/g," "); 
              } 
              i++; 
            }); 
             
            customCache.clear(); 
            dataArr.each(function(){ 
              customCache.add(this); 
            }); 
          }           
           
          //事件处理 
          options = options || {}; 
          this.onDataBinding = options.onDataBinding || this.onDataBinding; 
          this.onRowBinding = options.onRowBinding || this.onRowBinding; 
          this.onRowBinded = options.onRowBinded || this.onRowBinded;          
           
          function loadHeader(){ 
            var tr = table.firstChild; 
            if(tr && tr.nodeType != 1){ 
              tr = util.next(tr); 
            } 
            if(!/tr/i.test(tr.tagName)){ //如果第一个元素不是tr,则浏览器支持tbody 
              tr = tr.firstChild; 
              if(tr.nodeType != 1){ 
                tr = util.next(tr); 
              } 
            } 
            return tr; 
          } 
           
          function loadTemplate(){ 
            tr = util.next(header);//获取模板行 
            return tr; 
          } 
           
          function loadDataFormat(){ 
            var nodes = templateRow.childNodes,ele,data,result = {},attr; 
            nodes = util.parseArray(nodes); 
            nodes.each(function(i){ 
              ele = this; 
              if(ele && ele.nodeType == 1){ 
                attr = ele.data || ele.getAttribute("data"); 
                if(attr){ 
                  data = util.parseJSON(attr); 
                  ele.field = data.field; 
                  result[ele.field] = data; 
                } 
              } 
            });            
            return result; 
          } 
           
          function createSaveButton(){ 
            var div = document.createElement("div"); 
            div.style.position = "absolute"; 
            div.style.display = "none"; 
            div.style.width = "auto"; 
            var btn = document.createElement("button"); 
            btn.innerHTML = btn.innerText = btn.textContent = btn.value = "Save"; 
            try{ 
              btn.type = "button"; 
            }catch(e){ 
              btn.setAttribute("type","button"); 
            } 
            div.appendChild(btn); 
             
            var btnCancel = document.createElement("button"); 
            btnCancel.innerHTML = btnCancel.innerText = btnCancel.textContent = btnCancel.value = "Cancel"; 
            try{ 
              btnCancel.type = "button"; 
            }catch(e){ 
              btnCancel.setAttribute("type","button"); 
            } 
            div.appendChild(btnCancel); 
             
            document.body.appendChild(div); 
            Event.on.call(btn,"click",function(){ 
              self.save(); 
            }); 
            Event.on.call(btnCancel,"click",function(){ 
              div.style.display = "none"; 
              if(self.__editRow){ 
                self.__editRow.parentNode.removeChild(self.__editRow); 
                self.__editRow = null; 
              } 
            }); 
             
            return div; 
          } 
           
          function exec(){ 
            if(self.__editRow){//如果当前处于编辑模式,则禁用所有command 
              return; 
            } 
            var commandName = this.commandName; 
            var handler = self.__cache["commandHandles"][commandName];            
            if(handler){ 
              handler.call(this); 
            } 
          } 
           
          //去除模板行 
          templateRow.parentNode.removeChild(templateRow); 
           
          //处理表格中的command事件 
          var elements = header.getElementsByTagName("*"); 
          elements = util.parseArray(elements); 
          elements.each(function(){ 
            if(this.nodeType === 1){ 
              var commandName = this.command || this.getAttribute("command"); 
              if(commandName){ 
                self.__regCommand.call(this,commandName,header); 
              } 
            } 
          }); 
        }, 
        //bangding 
        bind:function(data){ 
          this.clear(); 
          if(data && data.length > 0){ 
            var self = this; 
            data.each(function(){ 
              self.append(this); 
            }); 
          } 
        }, 
        //清理表,删除所以除header以外的数据行 
        clear:function(){ 
          var rows = this.__cache["dataRows"],row; 
          rows.each(function(){ 
            row = this; 
            if(row){ 
              row.parentNode.removeChild(row); 
            } 
          }); 
          rows.clear();//清理rows 
        }, 
        //删除指定的行 
        removeRow:function(rowIndex){ 
          var rows = this.__cache["dataRows"]; 
          var row = rows.get(rowIndex); 
          if(row){ 
            var data = this.__cache["customCache"][rowIndex]; 
            row.parentNode.removeChild(row); 
            rows.remove(rowIndex); 
            //通知用户数据行被移除             
            if(util.isFunction(this.onRowRemoved)){ 
              this.onRowRemoved(data,row); 
            } 
          } 
          this.__removeRowCallback(); 
        }, 
        //添加 行  
        append:function(data){ 
          if(!data){ 
            return ; 
          } 
          var template = this.__cache["template"]; 
          var rows = this.__cache["dataRows"]; 
          var rowIndex = rows.length; 
          var tr = template.cloneNode(); 
          var customCache = this.__cache["customCache"]; 
          customCache.add(data); 
          //将数据行添加到table 
          this.__root.appendChild(tr); 
          var self = this; 
          var td,//数据单元格 
            dataFormat,//数据格式化器 
            value;//单元格中的给定的数据 
          tr.setAttribute("index",rowIndex.toString()); 
          //更改样式 
          if(rowIndex % 2 == 1){ 
            tr.className = (tr.className || "") + " odd"; 
          } 
          //通知 行数据绑定开始 
          if(util.isFunction(this.onRowBinding)){ 
            this.onRowBinding(rowIndex,tr); 
          } 
           
          var templateTD = template.firstChild; 
          while(templateTD){ 
            td = templateTD.cloneNode(true); 
            tr.appendChild(td); 
            if(td.nodeType == 1 && templateTD.field){ 
              dataFormat = this.__cache["dataFormat"][templateTD.field]; 
              td.removeAttribute("data"); 
              td.field = templateTD.field; 
              value = data[dataFormat.field]; 
              //通知单元格数据绑定事件 
              value = this.onDataBinding(dataFormat.field,value,td,data); 
              if(value !== false){//如果返回false,则不用做赋值操作 
                switch(dataFormat.render){ 
                  case "innerHTML": 
                    td.innerHTML = typeof value == "undefined" || value == null ? "" : value; 
                    break; 
                  case "innerText": 
                  default: 
                    td.innerText = td.textContent = typeof value == "undefined" || value == null ? "" : value; 
                    break; 
                } 
              } 
            } 
            templateTD = templateTD.nextSibling; 
          } 
          rows.add(tr); 
           
          //处理command 
          var elements = tr.getElementsByTagName("*"),ele,attr; 
          elements = util.parseArray(elements); 
          elements.each(function(){ 
            ele = this; 
            if(ele.nodeType == 1 && (ele.command || ele.getAttribute("command"))){ 
              attr = ele.command || ele.getAttribute("command"); 
              self.__regCommand.call(ele,attr,tr); 
            } 
          }); 
           
          //通知 行数据绑定完成 
          if(util.isFunction(this.onRowBinded)){ 
            this.onRowBinded(rowIndex,tr); 
          } 
        }, 
        //手动产生新的输入行 
        newLine:function(){ 
          if(this.__editRow){//如果当前有存在编辑行,则直接返回,每次最多限制编辑一行数据 
            return; 
          } 
          var template = this.__cache["template"] ; 
          var row = this.__editRow = template.cloneNode(false); 
          var templateTD = template.firstChild; 
          var textareaList = []; 
                       
          while(templateTD){ 
            td = templateTD.cloneNode(true); 
            row.appendChild(td); 
            if(td.nodeType == 1){ 
              if(templateTD.field){ 
                td.field = templateTD.field; 
                td.innerHTML = ""; 
                var dataFormat = this.__cache["dataFormat"][templateTD.field]; 
                var textarea = null; 
                if(dataFormat.render == "innerHTML"){ 
                  textarea = document.createElement("textarea"); 
                }else{ 
                  textarea = document.createElement("input"); 
                  textarea.type = "text"; 
                } 
                textarea.style.display = "none"; 
                td.appendChild(textarea); 
                textareaList.push(textarea); 
              } 
            } 
            templateTD = templateTD.nextSibling; 
          } 
          //将数据行添加到table 
          this.__root.appendChild(row); 
           
          var height = row.offsetHeight, 
            width = row.offsetWidth, 
            offset = util.offset(row); 
             
          textareaList.each(function(){ 
            this.style.height = (0.8 * height) + "px"; 
            this.style.width = (0.8 * this.parentNode.offsetWidth) + "px"; 
            this.style.display = ""; 
          }); 
           
          var left = offset.left + width + 5; 
          var top = offset.top; 
          this.__saveContainer.style.top = top + "px"; 
          this.__saveContainer.style.left = left + "px"; 
          this.__saveContainer.style.height = this.__saveContainer.style.lineHeight = height + "px"; 
          this.__saveContainer.style.display = "block"; 
        }, 
        //保存手动产生的数据行数据 
        save:function(){ 
          if(!this.__editRow){ 
            return; 
          } 
           
          var row = this.__editRow; 
          var td = row.firstChild; 
          var data = {}; 
          while(td){ 
            if(td.nodeType === 1 && td.field){ 
              var dataFormat = this.__cache["dataFormat"][td.field]; 
              var textarea = null; 
              if(dataFormat.render == "innerHTML"){ 
                textarea = td.getElementsByTagName("textarea")[0]; 
              }else{ 
                textarea = td.getElementsByTagName("input")[0]; 
              } 
              value = textarea.value; 
              switch(dataFormat.dataType){ 
                case "number": 
                  value = util.trim(value); 
                  value = Number(value.length == 0 ? 0 : value); 
                  break; 
                default: 
                  break; 
              } 
              data[td.field] = value; 
            } 
            td = td.nextSibling; 
          } 
          this.__editRow.parentNode.removeChild(this.__editRow); 
          this.__editRow = null; 
          this.__saveContainer.style.display = "none"; 
           
          //通知用户正在保存数据 
          if(util.isFunction(this.onSaving)){ 
            this.onSaving(data); 
          } 
           
          this.append(data); 
        }, 
        getRowData:function(rowIndex){ 
          return this.__cache["customCache"].get(rowIndex); 
        }, 
         
        //数据绑定到指定cell时的事件 
        onDataBinding:function(field,value,cell,data){ 
          return value; 
        }, 
        //当数据行绑定开始时的事件 
        onRowBinding:function(rowIndex, row){ 
        }, 
        //当数据行绑定完成时的事件 
        //@param row {DOM element tr}  
        onRowBinded:function(rowIndex, row){ 
        }, 
        //当编辑的数据被保存时的事件 
        onSaving:function(data){ 
        }, 
        //当数据行被移除时的通知事件 
        onRowRemoved:function(data,row){ 
        } 
      }; 
       
      grid.guid = 0; 
    })(); 
     
     
  </script> 
</head> 
 
<body> 
  <table id="table_demo" class="grid"> 
    <tr class="odd"> 
      <th>ID</th> 
      <th>Name</th> 
      <th>Descpription</th> 
      <th><button type="button" command="newLine" class="btn">New Line</button></th> 
    </tr> 
    <tr> 
      <td data='{"field":"id","dataType":"number","render":"innerText"}'>1</td> 
      <td data='{"field":"name","dataType":"string","render":"innerText"}'>WorkingService</td> 
      <td data='{"field":"description","dataType":"string","render":"innerHTML"}'>WorkingService</td> 
      <td> 
        <button type="button" command="removeRow" class="btn">Delete</button> 
      </td> 
    </tr> 
  </table> 
  <script type="text/javascript"> 
    var table = document.getElementById("table_demo"); 
    var g = new grid(table,{ 
      onDataBinding:function(field,value){ 
        return value; 
      }, 
      onRowBinded:function(rowIndex,row){} 
    }); 
    g.bind([ 
      {id:0,name:"kilin"}, 
      {id:1,name:"kilin1"}, 
      {id:2,name:"kilin2"}, 
      {id:3,name:"kilin3"} 
    ]); 
  </script> 
</body> 
</html>
Javascript 相关文章推荐
JavaScript 入门·JavaScript 具有全范围的运算符
Oct 01 Javascript
Jquery从头学起第四讲 jquery入门教程
Aug 01 Javascript
用jQuery实现的智能隐藏、滑动效果的返回顶部代码
Mar 18 Javascript
JS阻止用户多次提交示例代码
Mar 26 Javascript
AngularJS HTML编译器介绍
Dec 06 Javascript
jquery实现不包含当前项的选择器实例
Jun 25 Javascript
jQuery实现鼠标选文字发新浪微博的方法
Apr 02 Javascript
深入理解react-router@4.0 使用和源码解析
May 23 Javascript
node实现简单的反向代理服务器
Jul 26 Javascript
JavaScript交换变量常用4种方法解析
Sep 02 Javascript
vue实现简单数据双向绑定
Apr 28 Vue.js
JavaScript中MutationObServer监听DOM元素详情
Nov 27 Javascript
Javascript中call与apply的学习笔记
Sep 22 #Javascript
Javascript中this的用法详解
Sep 22 #Javascript
JavaScript的作用域和块级作用域概念理解
Sep 21 #Javascript
JavaScript中双叹号!!作用示例介绍
Sep 21 #Javascript
原生JavaScript实现合并多个数组示例
Sep 21 #Javascript
仿淘宝TAB切换搜索框搜索切换的相关内容
Sep 21 #Javascript
将数字转换成大写的人民币表达式的js函数
Sep 21 #Javascript
You might like
在Win7 中为php扩展配置Xcache
2014/10/08 PHP
php程序员应具有的7种能力小结
2014/11/27 PHP
在Linux系统的服务器上隐藏PHP版本号的方法
2015/06/06 PHP
YII框架中搜索分页jQuery写法详解
2016/12/19 PHP
优化 JavaScript 代码的方法小结
2009/07/16 Javascript
javascript 设计模式之单体模式 面向对象学习基础
2010/04/18 Javascript
javascript学习笔记(五)原型和原型链详解
2014/10/08 Javascript
JavaScript错误处理
2015/02/03 Javascript
thinkphp实现无限分类(使用递归)
2015/12/19 Javascript
浅析AngularJS Filter用法
2015/12/28 Javascript
jQuery事件绑定方法学习总结(推荐)
2016/11/21 Javascript
JS敏感词过滤代码
2016/12/23 Javascript
JavaScript结合HTML DOM实现联动菜单
2017/04/05 Javascript
详解javascript 正则表达式之分组与前瞻匹配
2018/05/30 Javascript
Vue中Quill富文本编辑器的使用教程
2018/09/21 Javascript
vue-cli配置全局sass、less变量的方法
2019/06/06 Javascript
vue cli3.0打包上线静态资源找不到路径的解决操作
2020/08/03 Javascript
如何构建一个Vue插件并生成npm包
2020/10/26 Javascript
python 参数列表中的self 显式不等于冗余
2008/12/01 Python
python冒泡排序算法的实现代码
2013/11/21 Python
剖析Django中模版标签的解析与参数传递
2015/07/21 Python
Python使用PIL库实现验证码图片的方法
2016/03/11 Python
python3.6+opencv3.4实现鼠标交互查看图片像素
2018/02/26 Python
Python 装饰器实现DRY(不重复代码)原则
2018/03/05 Python
python 列表中[ ]中冒号‘:’的作用
2019/04/30 Python
python 根据字典的键值进行排序的方法
2019/07/24 Python
TensorFlow打印输出tensor的值
2020/04/19 Python
Python实现邮件发送的详细设置方法(遇到问题)
2021/01/18 Python
美国乡村商店:Plow & Hearth
2016/09/12 全球购物
伦敦剧院及景点门票:Encore Tickets
2018/07/01 全球购物
体育专业个人的求职信范文
2013/09/21 职场文书
亲子活动总结
2014/04/26 职场文书
计算机专业自荐信
2014/05/24 职场文书
2014银行授权委托书样本
2014/10/04 职场文书
2014年妇幼卫生工作总结
2014/12/09 职场文书
Python 中的单分派泛函数你真的了解吗
2021/06/22 Python