javascript - 使用 mousedown 跨越表格的行并在 jquery 中拖动?

标签 javascript jquery html indexing html-table

我正在尝试制定一个时间表,我可以单击任何“时间”行并向下拖动以跨越该行,直到我“鼠标悬停”的行。例如,如果我在上午 7:30 点向下单击并向下拖动到 9:00,表数据元素将跨越适当的行数,以便表数据在该列中从 7:30 到 9:00 成为一个 block (即星期一)。这是“添加预约”按钮的功能。

我的计划是当我单击向下时存储 tr 的索引值,然后从我悬停到的 tr 的索引中减去该值(当鼠标按下时)。例如,如果我在第 1 行处向下单击,拖动到第 3 行,然后向上移动鼠标,则第一次单击的 td 的 rowspan 属性应设置为 2。

目前,我的函数将跨越多行,仅取决于我悬停的距离。所以它显然没有从点击中减去初始索引。我不知道为什么。有什么建议吗?

https://jsfiddle.net/Adam_M/fypw7jka/

这是我的时间表和按钮的 HTML:

   <div class="row" id="control-panel">
    <button onclick="addAppt()" id="add-appt" title="Add Appointment">+</button>
    <p>= Add Appointment</p>
    <button onclick="delAppt()" id="del-appt" title="Delete Appointment">-</button>
    <p>= Delete Appointment</p>
</div>

<table>
      <thead>
        <tr class="days-of-the-week">
          <th scope="col" class="time-col"></th>
          <th scope="col">Sunday</th>
          <th scope="col">Monday</th>
          <th scope="col">Tuesday</th>
          <th scope="col">Wednesday</th>
          <th scope="col">Thursday</th>
          <th scope="col">Friday</th>
          <th scope="col">Saturday</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th scope="row">7:30 AM</th>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
        </tr>
        <tr>
          <th scope="row">8:00 AM</th>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
        </tr>
        <tr>
          <th scope="row">8:30 AM</th>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
        </tr>
        <tr>
          <th scope="row">9:00 AM</th>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
          <td rowspan=""><textarea cols="20" rows="5" class="appt-text"></textarea></td>
        </tr>
      </tbody>
</table>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<script type="text/javascript" src="scheduler.js"></script>

相关函数的Javascript:

function addAppt() {
$('td').css('cursor', 'cell');
$('textarea').css('cursor', 'cell');
$('td').mousedown(function(){
    var initIndex = $(this).parent().index(); 
    $('td').hover(function(){
        var spanCount = $(this).parent().index(); 
        var span = spanCount - initIndex;
        $(this).attr( 'rowspan', span);
        $(this).addClass('highlight');
      });
});
$('td').mouseup(function(){
  $('td').off('mouseenter mouseleave');
});
}

最佳答案

这比我预想的要困难。但无论如何...

$(function() {

  var $table = $("#myTable tbody");
  var $rows = $table.children("tr");
  var $cells = $table.find("td").not(".rowHdr");

  var numCells = $cells.length;
  var numRows = $rows.length;
  var numCols = numCells / numRows; // skip row headings

  // track which columns have rowspans by setting to 1
  var matrix = new Array(numRows).fill(new Array(numCols).fill(0));

  var matrix = new Array(numRows);
  // init 2d matrix
  for (var i = 0; i < 10; i++) {
    matrix[i] = new Array(numCols);
  }
  //matrix[1][3] = 1; // test blocking cell
  var startCol, startRow, endRow, lastValidCell;

  var cellDown, cellOver, cellUp;
  var mouseDown = false;

  // used mouse event code from http://stackoverflow.com/a/19164149/1544886
  $cells.on('mousedown touchstart', function(event) {
    var cellPos;

    cellDown = this;

    event.preventDefault();
    mouseDown = true;

    cellPos = findCell(cellDown);

    if (cellPos) {
      startCol = cellPos.col;
      startRow = endRow = cellPos.row;
      highlightCells();
    } else {
      clearHighlights();
    }
  });

  $cells.on('mousemove touchmove', function(event) {
    event.preventDefault();

    if (mouseDown && cellOver != this) {
      var cellPos;

      cellOver = this;
      cellPos = findCell(cellOver);

      if (cellPos) {
        // limit to starting column only
        if (cellPos.col === startCol) {
          endRow = cellPos.row;
          highlightCells();
        }
      }
    }
  });

  $cells.on('mouseup touchend', function(event) {
    var cellPos;

    event.preventDefault();

    cellUp = this;
    cellPos = findCell(cellUp);

    if (cellPos && cellUp === lastValidCell) {
      createCellSpan();
    }
  });

  $(window.document).on('mouseup touchend', function(event) {
    mouseDown = false;
    //cellDown = cellOver = null;
    clearHighlights();
  });

  function findCell(cell) {
    var col, row;

    $cells.each(function(idx, el) {
      if (cell === el) {
        col = idx % numCols;
        row = Math.floor(idx / numCols);

        if (matrix[row][col] === 1) { // a rowspan already exists for this cell
          //console.log('found', row, col);
          col = null;
        }
        return false;
      }
    });

    return (col != null) ? {
      col: col,
      row: row
    } : null;
  }

  function highlightCells() {

    clearHighlights();

    if (endRow >= startRow) {
      for (var row = startRow; row <= endRow; row++) {
        if (matrix[row][startCol] !== 1) { // rowspan doesn't already exists for this cell
          var $thisCell = $cells.eq(row * numCols + startCol);
          $thisCell.addClass('highlight');
          lastValidCell = $thisCell[0];
        } else {
          endRow = row - 1; // found a blocking cell
          return false;
        }
      }
    } else {
      for (var row = startRow; row >= endRow; row--) {
        if (matrix[row][startCol] !== 1) { // rowspan doesn't already exists for this cell
          var $thisCell = $cells.eq(row * numCols + startCol);
          $thisCell.addClass('highlight');
          lastValidCell = $thisCell[0];
        } else {
          endRow = row + 1; // found a blocking cell
          return false;
        }
      }
    }
  }

  function clearHighlights() {
    $cells.removeClass('highlight');
  }

  function createCellSpan() {
    var sRow = Math.min(startRow, endRow);
    var eRow = Math.max(startRow, endRow);
    var rowSpan = eRow - sRow + 1;
    
    
    for (var row = eRow; row >= sRow; row--) {
      var $thisCell = $cells.eq(row * numCols + startCol);
      if (row === sRow)
        $thisCell.attr('rowspan', rowSpan).addClass('spanned');
      else 
        $thisCell.remove();
      matrix[row][startCol] = 1; // mark these cells as blocked
    } 

    /*for (var row = sRow; row <= eRow; row++) {
      var $thisCell = $cells.eq(row * numCols + startCol);
      $thisCell.addClass('spanned');
      matrix[row][startCol] = 1; // mark these cells as blocked
    } */
  }

});
.highlight {
  background-color: yellow;
}

.spanned {
  background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="myTable" border="1" cellpadding="10">
  <thead>
    <tr>
      <th></th>
      <th>A</th>
      <th>B</th>
      <th>C</th>
      <th>D</th>
      <th>E</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="rowHdr">1</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td class="rowHdr">2</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td class="rowHdr">3</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td class="rowHdr">4</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td class="rowHdr">5</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
    <tr>
      <td class="rowHdr">6</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
  </tbody>

关于javascript - 使用 mousedown 跨越表格的行并在 jquery 中拖动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42569531/

相关文章:

javascript - 基于表格中不同标题的css表格排序

javascript - 导出 npm 库模块的所有类

javascript - 是否可以独立运行jquery/javascript脚本?

javascript - Firebase - 从嵌套结构中提取对象的数据结构问题

javascript - Head First C Google map 与 JSON 文件关联

javascript - 触发 jQuery ("#collapseMenu").hide();按 Esc 键时

Jquery clone() 似乎不适用于 Mustaches

html - 图片旁边的文本框

javascript - 使用 Jquery cookie 存储 div 的切换状态?

javascript - slider 横幅过渡从选定的幻灯片开始