cson单机,【CSON原创】 支持行拖动,列拖动的表格插件

效果预览:
支持行拖动,列拖动的表格插件 col1_head col2_head col3_head col4_head
1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
4 6 7 8

功能说明:
当鼠标移动到表头区域时可以对列进行拖动排序,鼠标移动到行区域时可以对行进行拖动排序。
支持IE6 7 8 firefox chrome
实现原理:
当鼠标在表头区域按下时,复制现有的table(不复制其后代结点),并把选择列的所有元素复制添加到新table中,通过按下时的鼠标位置和鼠标移动坐标,确定新table的位置,在行区域按下时同理。
代码分析:
var SortTable = (function() { return function(sTableId, options) { this.init(sTableId, options); } })();
首先在构造函数里调用sortTable的init方法进行初始化。需要传入table的id和自定义选项对象,该对象里面包含用户自定义的属性值,对于没有传入的值,使用默认值。
SortTable.prototype = (function() { var dragTable; //保存拖动的table var isDragCol = false; //是否拖动列 var isDragsRow = false; //是否拖动行 var dragingIndex; //拖动的列索引或行索引 /* 点击位置相对于元素位置的位置对象 */ var relPos = { left: 0, top: 0, updatePos: function(left, top) { //更新目前的相对位置 this.left = left; this.top = top; } };
首先prototype里面有四个私有变量:
1.拖动中的table的引用:就是拖动行或者拖动列对象的引用
2.是否拖动列的布尔值:用户mouseover事件处理程序中判断是否处于拖动列的状态中,
3.是否拖动行的布尔值:用户mouseover事件处理程序中判断是否处于拖动列的状态中,
4.拖动行/列的索引:就是拖动的行或者列的索引值,用于查找该行/列并复制成新的table对象。
/* 设定索引和左位置值 */ var setIndexAndPos = function(elems, dir) { dir = dir || 'left'; for (var i = 0, len = elems.length; i < len; i++) { elems[i].index = i; if (dir == 'left') { elems[i].posLeft = util.getCurrentPosition(elems[i]).left; } else if (dir == 'top') { elems[i].posTop = util.getCurrentPosition(elems[i]).top; } } };
该私有方法在初始化过程中被调用,遍历元素集合,并设置其index和left或top的位置值。其中left值用于列拖动,top值用于行拖动,设定哪个值根据用户传入的dir来判断。
/* 设置新结点的样式 */ var setNewNodeStyle = function(newNode, nodeToClone) { var newStyle = newNode.style; var oldStyle = util.getComputedStyle(nodeToClone); newStyle.paddingLeft = oldStyle.paddingLeft; newStyle.paddingRight = oldStyle.paddingRight; newStyle.paddingTop = oldStyle.paddingTop; newStyle.paddingBottom = oldStyle.paddingBottom; newStyle.width = nodeToClone.clientWidth - parseInt(newStyle.paddingLeft) - parseInt(newStyle.paddingRight) + 'px'; newStyle.height = nodeToClone.clientHeight - parseInt(newStyle.paddingTop) - parseInt(newStyle.paddingBottom) + 'px'; }
用于根据某结点设定新结点的样式,使新结点的样式和参考结点的样式相同。该私有方法将用于行拖动时使新table各个td的值和参考table中的一样,目的是使拖动行幻影的样式和表格中的行一致。
/* 把点击列整列结点复制到新table */ var copyCol = function(index, rows, dragingClass, oTable) { var newNode; var nodeToClone; var newTr; var newBody; dragTable = oTable.cloneNode(false); newBody = document.createElement('TBODY'); //ie下tr必须包在thead tbody或tfoot里 dragTable.appendChild(newBody); dragTable.className += ' ' + dragingClass; for (var i = 0, len = rows.length; i < len; i++) { newTr = document.createElement('TR'); nodeToClone = rows[i].cells[index]; newNode = nodeToClone.cloneNode(true); newTr.appendChild(newNode); newBody.appendChild(newTr); } document.body.appendChild(dragTable); }
之后的函数用于把所点击列的结点复制到新的table用作拖动幻影。需要注意的是对于IE,必须创建tbody元素,并把新table的tr包含在tbody里,否则新table的结点会显示不出来。另外新table需要添加拖动样式类,该类在初始化时由用户传入,决定拖动幻影的样式。
/* 复制行 */ var copyRow = function(oTr, dragingClass, oTable) { var newTd; var oldTd; var newBody; var dragTr; dragTable = oTable.cloneNode(false); newBody = document.createElement('TBODY'); dragTable.appendChild(newBody); dragTr = oTr.cloneNode(true); newBody.appendChild(dragTr); dragTable.className += ' ' + dragingClass; for (var i = 0, len = dragTr.cells.length; i < len; i++) { newTd = dragTr.cells[i]; oldTd = oTr.cells[i]; setNewNodeStyle(newTd, oldTd); } document.body.appendChild(dragTable); }
复制行的函数,方法和复制列大致一样,通过创建新table,并根据所拖动行的索引获取对应的tr,把该tr复制到新table中去,同样要记得创建tbody标签。
/* 拖动时更新位置 */ var updateDragingPosition = function(left, top) { dragTable.style.left = left + 'px'; dragTable.style.top = top + 'px'; }
该方法在每次触发mousemove事件时调用,作用是更新拖动幻影的位置坐标,使之随着鼠标的移动而移动。
/* 放置拖动列 */ var placeCol = function(left, headers, rows) { var halfDistant; var parent = headers[0].parent; var len = headers.length; if (left < headers[0].posLeft) { placeAllColCells(0, rows); return; } else { for (var i = 0; i < len; i++) { halfDistant = headers[i].posLeft + (headers[i].clientWidth / 2); if (left >= headers[i].posLeft && left < halfDistant) { placeAllColCells(i, rows); return; } else if (left >= halfDistant && left < headers[i].posLeft + headers[i].clientWidth) { placeAllColCells(i + 1, rows); return; } } placeAllColCells(i, rows); } };
该方法用于在每次鼠标松开时,把选定的列插入到目标位置。在确定位置之前会左三个判断:
1.首先判断目前拖动幻影左位置是否小于第一个表头的左位置,是则把选定列插入到第一个列之前。
2.逐个判断处于列的前半部分还是后半部分,如果是前半部分,则插入到该列的之前,否则插入到该列之后。
3.如果之前的情况都不符合,则把结点插入到列集合的最尾。
/* 放置拖动列的所有结点 */ var placeAllColCells = function(index, rows) { for (var i = 0, len = rows.length; i < len; i++) { var parent = rows[i].cells[0].parentNode; if (index == rows[i].cells.length) { parent.appendChild(rows[i].cells[dragingIndex]); } else { parent.insertBefore(rows[i].cells[dragingIndex], rows[i].cells[index]); } } }
函数在上面的函数确定了插入列位置之后,使用该函数进行具体的插入操作,其中如果传入的i和length相等,则表示需要插入到列集合的最后,这时需要用appendchild而非insertbefore(虽然非IE的浏览器中insertbefore可以使用不存在的“尾结点”作为参考点来进行插入操作,但是IE会报错,所以为了兼容,还是应该使用appendchild进行插入)。
/* 放置拖动行 */ var placeRow = function(top, rows) { var halfDistant; var parent = rows[0].parentNode; var len = rows.length; if (top < rows[0].posTop) { parent.insertBefore(rows[dragingIndex], rows[0]); return; } else { for (var i = 0; i < len; i++) { halfDistant = rows[i].posTop + (rows[i].clientHeight / 2); if (top >= rows[i].posTop && top < halfDistant) { parent.insertBefore(rows[dragingIndex], rows[i]); return; } else if (top >= halfDistant && top < rows[i].posTop + rows[i].clientHeight) { i + 1 < len ? parent.insertBefore(rows[dragingIndex], rows[i + 1]) : parent.appendChild(rows[dragingIndex]); return; } } parent.appendChild(rows[dragingIndex]); } };
放置拖动行的函数,该函数思路和放置拖动列的差不多,也是通过对三种情况的判断,确定行插入位置,再进行具体的插入操作,详细可以参考上面的列插入操作。
/* 删除拖动幻影列 */ var removeShadowArray = function() { document.body.removeChild(dragTable); };
该函数用于在鼠标松开时,删除拖动幻影。
/* 鼠标按下事件处理程序 */ var downHandler = function(rows, dragingClass, oTable, _disibledevent=>return function(event) { var _elemPosition; var event = util.getEventObj(event); var target = util.getEventTarget(event); var selectedTr; if (target.tagName !== 'TH' && target.tagName !== 'TD' && target.parentNode.tagName !== 'TH') { return; } else { _disibledevent=>//执行开始拖动的回调函数 if (target.tagName == 'TH') { //判断点击是否为th(列拖动) dragingIndex = target.index; _elemPosition = util.getCurrentPosition(target); relPos.updatePos(event.clientX - _elemPosition.left, event.clientY - _elemPosition.top); copyCol(dragingIndex, rows, dragingClass, oTable); isDragCol = true; } else if (target.tagName == 'TD') { //判断点击是否为td(行拖动) selectedTr = target.parentNode; dragingIndex = selectedTr.index; _elemPosition = util.getCurrentPosition(selectedTr); relPos.updatePos(event.clientX - _elemPosition.left, event.clientY - _elemPosition.top); copyRow(selectedTr, dragingClass, oTable); isDragsRow = true; } updateDragingPosition(event.clientX - relPos.left, event.clientY - relPos.top); //更新拖动幻影位置 } } };
鼠标按下时的事件处理程序,其中的onBeginDrag是用户初始化时定义的开始拖动的回调函数。然后判断点击区域 ,再进行相应的行拖动或列拖动。最后调用updateDragingPosition函数更新拖动幻影的位置。
/* 鼠标拖动事件处理程序 */ var moveHandler = function(oTable, _disibledevent=>return function(event) { var event = util.getEventObj(event); var target = util.getEventTarget(event); if (isDragCol || isDragsRow) { _disibledevent=>- relPos.left, event.clientY - relPos.top, oTable); } } };
鼠标拖动的处理程序,其中如果是行拖动或者列拖动状态,则更新拖动幻影的坐标(行拖动和列拖动使用同一个更新函数)。并调用onDraging函数,该函数在初始化时由用户定义,在拖动期间执行。
/* 鼠标松开事件处理程序 */ var upHandler = function(headers, rows, tBodyRows, _disibledevent=>return function(event) { var event = util.getEventObj(event); var target = util.getEventTarget(event); if (!isDragCol && !isDragsRow) { return; } else { if (isDragCol) { placeCol(event.clientX - relPos.left, headers, rows); isDragCol = false; setIndexAndPos(headers, 'left'); } else if (isDragsRow) { placeRow(event.clientY - relPos.top, tBodyRows); isDragsRow = false; setIndexAndPos(tBodyRows, 'top'); } removeShadowArray(); _disibledevent=> /* 为事件添加处理程序 */ var addDragHandler = function(rows, dragingClass, oTable, headers, tBodyRows, _disibledevent=>'mousedown', downHandler(rows, dragingClass, oTable, _disibledevent=>'mousemove', moveHandler(oTable, _disibledevent=>'mouseup', upHandler(headers, rows, tBodyRows, _disibledevent=> return { /* 初始化 */ init: function(sTableId, options) { var defaults = { dragingClass: 'draging', _disibledevent=>this.oTable = util.$(sTableId); this.rows = this.oTable.rows; this.tHead = this.oTable.tHead; this.tBody = this.oTable.tBodies[0]; this.headers = this.tHead.rows[0].cells; this.dragingClass = defaults.dragingClass; this.onBeginDrag = util.bindFunction(defaults.onBeginDrag); this.onEndDrag = util.bindFunction(defaults.onEndDrag); this.onDraging = util.bindFunction(defaults.onDraging); setIndexAndPos(this.headers, 'left'); setIndexAndPos(this.tBody.rows, 'top'); addDragHandler(this.rows, this.dragingClass, this.oTable, this.headers, this.tBody.rows, this.onBeginDrag, this.onEndDrag, this.onDraging); } } })();
最后返回prototype对象,其中的init方法用户初始化。另外需要注意的是三个回调函数由于使用了bindFunction,因此它们调用时this指向该SortTable对象,可以方便地使用该对象中的属性值。
new SortTable('sTable');
最后是调用方法。
所有源代码:

【CSON原创】 支持行拖动,列拖动的表格插件cson单机【CSON原创】 支持行拖动,列拖动的表格插件cson单机View Code var SortTable = (function() { return function(sTableId, options) { this.init(sTableId, options); } })(); SortTable.prototype = (function() { var dragTable; //保存拖动的table var isDragCol = false; //是否拖动列 var isDragsRow = false;//是否拖动行 var dragingIndex; //拖动的列索引或行索引 /* 点击位置相对于元素位置的位置对象 */ var relPos = { left: 0, top: 0, updatePos: function(left, top) { this.left = left; this.top = top; } }; /* 设定索引和左位置值 */ var setIndexAndPos = function(elems, dir) { dir = dir || 'left'; for (var i = 0, len = elems.length; i < len; i++) { elems[i].index = i; if (dir == 'left') { elems[i].posLeft = util.getCurrentPosition(elems[i]).left; } else if (dir == 'top') { elems[i].posTop = util.getCurrentPosition(elems[i]).top; } } }; /* 设置新结点的样式 */ var setNewNodeStyle = function(newNode, nodeToClone) { var newStyle = newNode.style; var oldStyle = util.getComputedStyle(nodeToClone); newStyle.paddingLeft = oldStyle.paddingLeft; newStyle.paddingRight = oldStyle.paddingRight; newStyle.paddingTop = oldStyle.paddingTop; newStyle.paddingBottom = oldStyle.paddingBottom; newStyle.width = nodeToClone.clientWidth - parseInt(newStyle.paddingLeft) - parseInt(newStyle.paddingRight) + 'px'; newStyle.height = nodeToClone.clientHeight - parseInt(newStyle.paddingTop) - parseInt(newStyle.paddingBottom) + 'px'; } /* 把点击列整列结点复制到新table */ var copyCol = function(index, rows, dragingClass, oTable) { var newNode; var nodeToClone; var newTr; var newBody; dragTable = oTable.cloneNode(false); newBody = document.createElement('TBODY'); //ie下tr必须包在thead tbody或tfoot里 dragTable.appendChild(newBody); dragTable.className += ' ' + dragingClass; for (var i = 0, len = rows.length; i < len; i++) { newTr = document.createElement('TR'); nodeToClone = rows[i].cells[index]; newNode = nodeToClone.cloneNode(true); newTr.appendChild(newNode); newBody.appendChild(newTr); } document.body.appendChild(dragTable); } /* 复制行 */ var copyRow = function(oTr, dragingClass, oTable) { var newTd; var oldTd; var newBody; var dragTr; dragTable = oTable.cloneNode(false); newBody = document.createElement('TBODY'); dragTable.appendChild(newBody); dragTr = oTr.cloneNode(true); newBody.appendChild(dragTr); dragTable.className += ' ' + dragingClass; for (var i = 0, len = dragTr.cells.length; i < len; i++) { newTd = dragTr.cells[i]; oldTd = oTr.cells[i]; setNewNodeStyle(newTd, oldTd); } document.body.appendChild(dragTable); } /* 拖动时更新位置 */ var updateDragingPosition = function(left, top) { dragTable.style.left = left + 'px'; dragTable.style.top = top + 'px'; } /* 放置拖动列的所有结点 */ var placeAllColCells = function(index, rows) { for (var i = 0, len = rows.length; i < len; i++) { var parent = rows[i].cells[0].parentNode; if (index == rows[i].cells.length) { parent.appendChild(rows[i].cells[dragingIndex]); } else { parent.insertBefore(rows[i].cells[dragingIndex], rows[i].cells[index]); } } } /* 放置拖动列 */ var placeCol = function(left, headers, rows) { var halfDistant; var parent = headers[0].parent; var len = headers.length; if (left < headers[0].posLeft) { placeAllColCells(0, rows); return; } else { for (var i = 0; i < len; i++) { halfDistant = headers[i].posLeft + (headers[i].clientWidth / 2); if (left >= headers[i].posLeft && left < halfDistant) { placeAllColCells(i, rows); return; } else if (left >= halfDistant && left < headers[i].posLeft + headers[i].clientWidth) { placeAllColCells(i + 1, rows); return; } } placeAllColCells(i, rows); } }; /* 放置拖动行 */ var placeRow = function(top, rows) { var halfDistant; var parent = rows[0].parentNode; var len = rows.length; if (top < rows[0].posTop) { parent.insertBefore(rows[dragingIndex], rows[0]); return; } else { for (var i = 0; i < len; i++) { halfDistant = rows[i].posTop + (rows[i].clientHeight / 2); if (top >= rows[i].posTop && top < halfDistant) { parent.insertBefore(rows[dragingIndex], rows[i]); return; } else if (top >= halfDistant && top < rows[i].posTop + rows[i].clientHeight) { i + 1 < len ? parent.insertBefore(rows[dragingIndex], rows[i + 1]) : parent.appendChild(rows[dragingIndex]); return; } } parent.appendChild(rows[dragingIndex]); } }; /* 删除拖动幻影列 */ var removeShadowArray = function() { document.body.removeChild(dragTable); }; /* 鼠标按下事件处理程序 */ var downHandler = function(rows, dragingClass, oTable, _disibledevent=>return function(event) { var _elemPosition; var event = util.getEventObj(event); var target = util.getEventTarget(event); var selectedTr; if (target.tagName !== 'TH' && target.tagName !== 'TD' && target.parentNode.tagName !== 'TH') { return; } else { _disibledevent=>//执行开始拖动的回调函数 if (target.tagName == 'TH') { //判断点击是否为th(列拖动) dragingIndex = target.index; _elemPosition = util.getCurrentPosition(target); relPos.updatePos(event.clientX - _elemPosition.left, event.clientY - _elemPosition.top); copyCol(dragingIndex, rows, dragingClass, oTable); isDragCol = true; } else if (target.tagName == 'TD') { //判断点击是否为td(行拖动) selectedTr = target.parentNode; dragingIndex = selectedTr.index; _elemPosition = util.getCurrentPosition(selectedTr); relPos.updatePos(event.clientX - _elemPosition.left, event.clientY - _elemPosition.top); copyRow(selectedTr, dragingClass, oTable); isDragsRow = true; } updateDragingPosition(event.clientX - relPos.left, event.clientY - relPos.top); //更新拖动幻影位置 } } }; /* 鼠标拖动事件处理程序 */ var moveHandler = function(oTable, _disibledevent=>return function(event) { var event = util.getEventObj(event); var target = util.getEventTarget(event); if (isDragCol || isDragsRow) { _disibledevent=>- relPos.left, event.clientY - relPos.top, oTable); } } }; /* 鼠标松开事件处理程序 */ var upHandler = function(headers, rows, tBodyRows, _disibledevent=>return function(event) { var event = util.getEventObj(event); var target = util.getEventTarget(event); if (!isDragCol && !isDragsRow) { return; } else { if (isDragCol) { placeCol(event.clientX - relPos.left, headers, rows); isDragCol = false; setIndexAndPos(headers, 'left'); } else if (isDragsRow) { placeRow(event.clientY - relPos.top, tBodyRows); isDragsRow = false; setIndexAndPos(tBodyRows, 'top'); } removeShadowArray(); _disibledevent=>/* 为事件添加处理程序 */ var addDragHandler = function(rows, dragingClass, oTable, headers, tBodyRows, _disibledevent=>'mousedown', downHandler(rows, dragingClass, oTable, _disibledevent=>'mousemove', moveHandler(oTable, _disibledevent=>'mouseup', upHandler(headers, rows, tBodyRows, _disibledevent=>return { /* 初始化 */ init: function(sTableId, options) { var defaults = { dragingClass: 'draging', _disibledevent=>this.oTable = util.$(sTableId); this.rows = this.oTable.rows; this.tHead = this.oTable.tHead; this.tBody = this.oTable.tBodies[0]; this.headers = this.tHead.rows[0].cells; this.dragingClass = defaults.dragingClass; this.onBeginDrag = util.bindFunction(defaults.onBeginDrag); this.onEndDrag = util.bindFunction(defaults.onEndDrag); this.onDraging = util.bindFunction(defaults.onDraging); setIndexAndPos(this.headers, 'left'); setIndexAndPos(this.tBody.rows, 'top'); addDragHandler(this.rows, this.dragingClass, this.oTable, this.headers, this.tBody.rows, this.onBeginDrag, this.onEndDrag, this.onDraging); } } })();

欢迎转载,请标明出处:http://www.cnblogs.com/Cson/archive/2011/07/08/2101317.html
Tags:  wp伪原创插件 word表格拖动 cson下载 cson单机

延伸阅读

最新评论

发表评论