【问题标题】:Span rows of a table with mousedown and drag in jquery?用mousedown跨越表格的行并在jquery中拖动?
【发布时间】:2017-07-23 00:16:56
【问题描述】:

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

我的计划是在我单击时存储 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');
});
}

【问题讨论】:

  • 你的小提琴不起作用 - 它缺少脚本scheduler.js
  • @KScandrett 当我点击它时它会起作用......我只是将脚本从 scheduler.js 复制并粘贴到 jsfiddle 的 javascript 部分。它应该在那里。
  • 这是我在上面描述的尝试的更新小提琴。 jsfiddle.net/Adam_M/fypw7jka/5 这些行是根据我单击的行的索引来跨越的。所以变量 initIndex 并没有像我预期的那样被减去。当我拖动时,我还有一个意外的功能,即在表格的右侧添加了列。我不知道会发生这种情况。
  • 右侧添加的列是因为在创建rowspan 时需要从跨越的行中删除现有的td
  • @KScandrett 我通过右键单击在您的代码中添加了 removeCellSpan() 函数。整个编辑在您编写的函数内(本地到)。到目前为止,我从您的代码中学到了很多东西,并且进展顺利。但我试图弄清楚还有什么遗漏导致表格的其余部分无法识别新附加的元素。我试图让一切恢复到原来的状态。我注意到在删除跨度并添加元素后,$thisCell 之后的行实例无法再次突出显示。对于这些行,矩阵似乎变成了一列。有什么想法吗?

标签: javascript jquery html indexing html-table


【解决方案1】:

这比我预期的要困难得多。不过不管怎样……

$(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>

【讨论】:

  • 这太棒了!谢谢!这几天我一直在为此苦苦挣扎
  • 我也花了一段时间(约 3 小时)。一些挑战是正确的。但一旦我开始,我想我还不如完成它。
  • 我不会撒谎的。这段代码比我能理解的要高级得多。但是如果我花时间仔细阅读它,我相信我可以学到很多东西。感谢您的诚实努力。一旦我能理解你所做的事情,我可能会立即使用它。
  • 我建议在整个过程中添加大量console.log()s 以帮助理解。代码的一个重要部分是确保它们不会与任何现有的行跨度发生冲突(行跨度信息存储在数组matrix 中),并且只能选择起始列中的单元格。
【解决方案2】:

daver182 的代码也可以在这里看到http://jsfiddle.net/daver182/cB4UQ/1/

$(function () {
  var isMouseDown = false,
    isHighlighted;
 var currentCol;
  $("#our_table td")
    .mousedown(function () {
      isMouseDown = true;
      currentCol = this.getAttribute("data-col");
      $(this).toggleClass("highlighted");
      isHighlighted = $(this).hasClass("highlighted");
      return false; // prevent text selection
    })
    .mouseover(function () {
      if (isMouseDown) {
          if(currentCol === this.getAttribute("data-col")){
              $(this).toggleClass("highlighted", isHighlighted);
          }
      }
    })
    .bind("selectstart", function () {
      return false;
    })

  $(document)
    .mouseup(function () {
      isMouseDown = false;
    });
});
table td {
  width:100px;
  height:100px;
  text-align:center;
  vertical-align:middle;
  background-color:#ccc;
  border:1px solid #fff;
}

table td.highlighted {
  background-color:#999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<table cellpadding="0" cellspacing="0" id="our_table">
  <tr>
    <td data-row="1" data-col="1">a</td>
    <td data-row="1" data-col="2">b</td>
    <td data-row="1" data-col="3">c</td>
  </tr>
  <tr>
    <td data-row="2" data-col="1">d</td>
    <td data-row="2" data-col="2">e</td>
    <td data-row="2" data-col="3">f</td>
  </tr>
  <tr>
    <td data-row="3" data-col="1">g</td>
    <td data-row="3" data-col="2">h</td>
    <td data-row="3" data-col="3">i</td>
  </tr>
</table>

【讨论】:

  • 感谢您的回复。在尝试跨越行之前,我已经可以使用我的代码执行此操作。我现在可能会使用与您类似的方法。但这并不能回答我如何通过拖动来跨越行的问题。我希望单击的 td 的实际 rowspan="" 属性根据我拖动的距离来更改其值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-05
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 1970-01-01
相关资源
最近更新 更多