使用vanila JS使表格行可以拖动。

问题描述 投票:0回答:1

我有一个像这样的简单表格。

╔═════════════╦═════════╦═════════╗
║     Col1    ║  Col2   ║  Col3   ║
╠═════════════╬═════════╬═════════╣
║ Value 1     ║ Value 2 ║ Value 3 ║
║ Value 4     ║ Value 5 ║ Value 6 ║
║ Value 7     ║ Value 8 ║ Value 9 ║
╚═════════════╩═════════╩═════════╝

我需要它的值的行是可以拖动的,这样我就可以改变它们的顺序。类似的方式 .sortable() 在jquery中可以使用,但我需要在vanila JS中使用。我已经找到了许多使用不同库的解决方案,但在纯JS中没有。

有足够简单的解决方案吗?我不需要动画或任何库提供的东西,只需要功能。

提前感谢你的任何形式的帮助。

javascript html html-table rows draggable
1个回答
0
投票

在codepen上找到了一个用vanila JS的工作方案。

https:/codepen.iochingypenExxvpjo?editors=1010。

JS

(function() {
  "use strict";

  const table = document.getElementById('table');
  const tbody = table.querySelector('tbody');

  var currRow = null,
      dragElem = null,
      mouseDownX = 0,
      mouseDownY = 0,         
      mouseX = 0,
      mouseY = 0,      
      mouseDrag = false;  

  function init() {
    bindMouse();
  }

  function bindMouse() {
    document.addEventListener('mousedown', (event) => {
      if(event.button != 0) return true;

      let target = getTargetRow(event.target);
      if(target) {
        currRow = target;
        addDraggableRow(target);
        currRow.classList.add('is-dragging');


        let coords = getMouseCoords(event);
        mouseDownX = coords.x;
        mouseDownY = coords.y;      

        mouseDrag = true;   
      }
    });

    document.addEventListener('mousemove', (event) => {
      if(!mouseDrag) return;

      let coords = getMouseCoords(event);
      mouseX = coords.x - mouseDownX;
      mouseY = coords.y - mouseDownY;  

      moveRow(mouseX, mouseY);
    });

    document.addEventListener('mouseup', (event) => {
      if(!mouseDrag) return;

      currRow.classList.remove('is-dragging');
      table.removeChild(dragElem);

      dragElem = null;
      mouseDrag = false;
    });    
  }


  function swapRow(row, index) {
     let currIndex = Array.from(tbody.children).indexOf(currRow),
         row1 = currIndex > index ? currRow : row,
         row2 = currIndex > index ? row : currRow;

     tbody.insertBefore(row1, row2);
  }

  function moveRow(x, y) {
    dragElem.style.transform = "translate3d(" + x + "px, " + y + "px, 0)";

    let dPos = dragElem.getBoundingClientRect(),
        currStartY = dPos.y, currEndY = currStartY + dPos.height,
        rows = getRows();

    for(var i = 0; i < rows.length; i++) {
      let rowElem = rows[i],
          rowSize = rowElem.getBoundingClientRect(),
          rowStartY = rowSize.y, rowEndY = rowStartY + rowSize.height;

      if(currRow !== rowElem && isIntersecting(currStartY, currEndY, rowStartY, rowEndY)) {
        if(Math.abs(currStartY - rowStartY) < rowSize.height / 2)
          swapRow(rowElem, i);
      }
    }    
  }

  function addDraggableRow(target) {    
      dragElem = target.cloneNode(true);
      dragElem.classList.add('draggable-table__drag');
      dragElem.style.height = getStyle(target, 'height');
      dragElem.style.background = getStyle(target, 'backgroundColor');     
      for(var i = 0; i < target.children.length; i++) {
        let oldTD = target.children[i],
            newTD = dragElem.children[i];
        newTD.style.width = getStyle(oldTD, 'width');
        newTD.style.height = getStyle(oldTD, 'height');
        newTD.style.padding = getStyle(oldTD, 'padding');
        newTD.style.margin = getStyle(oldTD, 'margin');
      }      

      table.appendChild(dragElem);


      let tPos = target.getBoundingClientRect(),
          dPos = dragElem.getBoundingClientRect();
      dragElem.style.bottom = ((dPos.y - tPos.y) - tPos.height) + "px";
      dragElem.style.left = "-1px";    

      document.dispatchEvent(new MouseEvent('mousemove',
        { view: window, cancelable: true, bubbles: true }
      ));    
  }  







  function getRows() {
    return table.querySelectorAll('tbody tr');
  }    

  function getTargetRow(target) {
      let elemName = target.tagName.toLowerCase();

      if(elemName == 'tr') return target;
      if(elemName == 'td') return target.closest('tr');     
  }

  function getMouseCoords(event) {
    return {
        x: event.clientX,
        y: event.clientY
    };    
  }  

  function getStyle(target, styleName) {
    let compStyle = getComputedStyle(target),
        style = compStyle[styleName];

    return style ? style : null;
  }  

  function isIntersecting(min0, max0, min1, max1) {
      return Math.max(min0, max0) >= Math.min(min1, max1) &&
             Math.min(min0, max0) <= Math.max(min1, max1);
  }  



  init();

})();

CSS:

.draggable-table {
     position: absolute;
     top: 25%;
     left: 20%;
     width: 60%;
     height: 50%;
     border-collapse: collapse;
     background: white;
     -webkit-box-shadow: 0px 0px 10px 8px rgba(0, 0, 0, 0.1);
     box-shadow: 0px 0px 10px 8px rgba(0, 0, 0, 0.1);
}
 .draggable-table .draggable-table__drag {
     font-size: 0.95em;
     font-weight: lighter;
     text-transform: capitalize;
     position: absolute;
     width: 100%;
     text-indent: 50px;
     border: 1px solid #f1f1f1;
     z-index: 10;
     cursor: grabbing;
     -webkit-box-shadow: 2px 2px 3px 0px rgba(0, 0, 0, 0.05);
     box-shadow: 2px 2px 3px 0px rgba(0, 0, 0, 0.05);
     opacity: 1;
}

HTML

<table id="table" class="draggable-table">
  <thead>
    <th>Name</th>
    <th>Occupation</th>
  </thead>
  <tbody>
    <tr>
      <td>April Douglas</td>
      <td>Health Educator</td>
    </tr>
    <tr>
      <td>Salma Mcbride</td>
      <td>Mental Health Counselor</td>
    </tr>  
    <tr>
      <td>Kassandra Donovan</td>
      <td>Makeup Artists</td>
    </tr> 
    <tr>
      <td>Yosef Hartman</td>
      <td>Theatrical and Performance</td>
    </tr>
    <tr>
      <td>Ronald Mayo</td>
      <td>Plant Etiologist</td>
    </tr>  
    <tr>
      <td>Trey Woolley</td>
      <td>Maxillofacial Surgeon</td>
    </tr>  
  </tbody>
</table>
© www.soinside.com 2019 - 2024. All rights reserved.