首页 > 其他 > 详细

Vue+ElementUl 自定义指令实现表格的列拖拽

时间:2020-11-03 16:56:12      阅读:301      评论:0      收藏:0      [点我收藏+]

自定义指令代码

Vue.directive(‘tableDrag‘, {
 update: function(el,binding,vnode) {
    var container=el.parentNode;
    var tbody=el.getElementsByClassName(‘el-table__body-wrapper‘)[0];
    var thead = el.getElementsByClassName(‘el-table__header-wrapper‘)[0];
    // 更新数据时,先还原数据本来的顺序,不然新加载的数据和表头对不上
    var trCollection=container.getElementsByTagName("tr");
    for (var i = 0; i < trCollection.length; i++) {
        var tr=trCollection[i];
        if(i==0){
            var collection=tr.getElementsByTagName("th");
        }else{
            var collection=tr.getElementsByTagName("td");
        }
        if(collection.length>1){
            let cellArr=[];
            for (let j = 0; j < collection.length; j++) {
                let cell=collection[j];
                let classNames=cell.className;
                let className=classNames.split(" ")[0];
                let arr=className.split("_");
                if(arr.length){
                    let index=arr[arr.length-1];
                    cellArr[index-1]=cell;
                }
            }
            for(let k=0;k<cellArr.length;k++){
                tr.insertBefore(cellArr[k],collection[k])
            }
        }
    }
   
    // 列拖拽开始...
    if(!container.className.includes(‘drag-table‘))container.className=" drag-table";
    thead.onmousedown = function(e) {
        const clickX=event.clientX
        const rect=event.target.getBoundingClientRect()
        const divLeft=rect.left
        const divRight=rect.right
        
        //拖动列
        if(event.target.tagName=="DIV"&&(clickX>divLeft+5&&clickX<divRight-5)){
            //被拖动的th
            var ev_th=event.target.parentNode;
            var scrollLeft=tbody.scrollLeft
            
            //算出鼠标相对元素的位置
            let disX = e.clientX + scrollLeft - ev_th.offsetLeft;
            let disY = e.clientY - ev_th.offsetTop;

            let thWidthArr = []; // 记录所有的th的宽度,依次累加
            let thWidthObj = {}; // 记录所有的th的宽度,依次累加
            let finallIndex = 0;//最终的th index
            let directionIndex = 0; // 单击的是第几个th
            let move=0; // 移动的方向 1-右 2-左

            const ths = ev_th.parentNode.children;
            var len=ths.length-1;// 删除elementUI最后的class="gutter"的元素
            for(let thi = 0;thi<len;thi++){
                const itemth = ths[thi];
                itemth.index = thi;
                thWidthArr.push(itemth.offsetLeft)
            }

            directionIndex = ev_th.index;
            // 以鼠标按下的这个th处,创建一个和th内容一样的div,
            const createDiv = document.createElement(‘div‘);
            createDiv.id = ‘created-div‘;
            container.appendChild(createDiv);

            document.onmousemove = (e)=>{
                // 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
                let left = e.clientX - disX;
                let top = e.clientY - disY;
                if(Math.abs(e.clientX - disX - ev_th.offsetLeft)<10){return;}
                //绑定元素位置到positionX和positionY上面

                //移动当前元素
                const thText = ev_th.innerHTML;
                createDiv.innerHTML = thText;
                createDiv.style.position = ‘absolute‘;
                createDiv.style.width = ev_th.offsetWidth + ‘px‘;
                createDiv.style.height = ev_th.offsetHeight + ‘px‘;
                createDiv.style.background = ‘#666‘;
                createDiv.style.lineHeight = ev_th.offsetHeight + ‘px‘;
                createDiv.style.textAlign = ‘center‘;
                createDiv.style.left = left + ‘px‘;
                createDiv.style.top = top + ‘px‘;

                finallIndex = 0; //鼠标拖动过程中所停留在的th的index

                var distance=createDiv.offsetLeft+scrollLeft
                var i=thWidthArr.length-1;
                while(i>=0){
                    if(distance>=thWidthArr[i]){
                        finallIndex=i;
                        break;
                    }
                    i--;
                }
            };
            document.onmouseup = (e) => {
                if(directionIndex<finallIndex){move=1}//右移
                else if(directionIndex>finallIndex){move=2}//左移
                const th_trs = thead.getElementsByTagName(‘tr‘);
                const td_trs = tbody.getElementsByTagName(‘tr‘);
                container.removeChild(createDiv);

                // 取消鼠标拖动和鼠标抬起事件
                document.onmousemove = null;
                document.onmouseup = null;

                // 如果没有进行拖动操作(鼠标点下就抬起)
                if(Math.abs(e.clientX - disX- ev_th.offsetLeft)<10){
                    thWidthArr = [];disX = 0;
                    return;
                }

                // 遍历tr,将th和td放到最终的位置上
                var itemtr=th_trs[0];
                if(itemtr.getElementsByTagName(‘th‘).length){
                    const ths = itemtr.getElementsByTagName(‘th‘);
                    if(move===1){
                        itemtr.insertBefore(ths[directionIndex],ths[finallIndex+1]);
                    }else if(move===2){
                        itemtr.insertBefore(ths[directionIndex],ths[finallIndex]);
                    }
                }
                for(let i = 0;i<td_trs.length;i++){
                    const itemtr = td_trs[i];
                    if(itemtr.getElementsByTagName(‘td‘).length){
                        const tds = itemtr.getElementsByTagName(‘td‘);
                        if(move===1){
                            itemtr.insertBefore(tds[directionIndex],tds[finallIndex+1]);
                        }else if(move===2){
                            itemtr.insertBefore(tds[directionIndex],tds[finallIndex]);
                        }
                    }
                }

                // 重置thWidthArr和disX
                thWidthArr = [];disX = 0;

            };
        }
    };
}});

全局css

.drag-table{ position: relative; -moz-user-select: none; -khtml-user-select: none; user-select: none; } .drag-table th{ cursor: move; }

模板绑定指令

<el-table v-table-drag border :data="tableData" @sort-change="sortChange" ">......</el-table>

注意事项

  • 在更新tableData的数据时,需要还原表头column的顺序,不然会导致表头和数据错位

Vue+ElementUl 自定义指令实现表格的列拖拽

原文:https://www.cnblogs.com/LunuZ/p/13900168.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!