用 JavaScript 实现,拖动元素在表格 (一个范围) 内移动

  • 注意:该案例基于 jQuery,需自行引入
  • 移动范围由 div 搭建(div 模仿表格),卡片的移动不允许超出该范围
  • 移动卡片会有一个淡蓝色卡片的标记出将要放置的位置
  • 有禁止放置标记的位置,不允许卡片放置(会放到前一个可放置的位置)
  • 卡片放置会覆盖单元格中的文字
  • 卡片上的文字会跟随卡片的移动而改变
  • 点击单元格,卡片会移动到该单元格

在这里插入图片描述

  • css 代码

    .week-table {
      width: 660px;
      position: relative;
    }
    
    .week-table .thead-tr,
    .week-table .tbody-tr {
      display: flex;
    }
    
    .week-table .thead-tr div,
    .week-table .tbody-tr div {
      text-align: center;
      flex: 0 0 87px;
      height: 25px;
      border-right: 1px solid #ddd;
      border-top: 1px #ddd dashed;
      line-height: 25px;
      user-select: none;
      position: relative;
    }
    
    .week-table .thead-tr div:last-child,
    .week-table .tbody-tr div:last-child {
      border-right: unset;
    }
    
    .week-table .thead-tr div:first-child,
    .week-table .tbody-tr div:first-child {
      border-left: 1px #ddd dashed;
      flex: 0 0 50px;
    }
    
    .week-table .thead-tr div:last-child,
    .week-table .tbody-tr div:last-child {
      border-right: 1px #ddd dashed;
    }
    
    .week-table .tbody-tr:last-child {
      border-bottom: 1px #ddd dashed;
    }
    
    .week-table .tr div:first-child {
      border-left: 1px #ddd dashed;
    }
    
    .week-table .thead-tr div {
      font-weight: bold;
      background-color: #f5f7fa;
    }
    
    .week-table .tbody-tr div:first-child {
      color: #fff;
    }
    
    .week-table .tbody-tr:nth-child(-n + 6) div:first-child {
      background-color: #3071a9;
    }
    
    .week-table .tbody-tr:nth-child(n + 7) div:first-child {
      background-color: #45b6b0;
    }
    
    .week-table .tbody-tr:nth-child(n + 11) div:first-child {
      background-color: #65c3df;
    }
    
    .week-table .tbody-tr .forbid {
      color: red;
      user-select: none;
      cursor: not-allowed;
    }
    
    .week-table .tbody-tr .card {
      background-color: #3071a9 !important;
      color: #333 !important;
      position: absolute;
      left: 1px;
      top: 1px;
      z-index: 2;
      user-select: none;
      border-radius: 4px;
    }
    
    .week-table .tbody-tr .highlight {
      background-color: #65c3df;
    }
    
  • HTML 代码

      <div class="week-table">
          <div class="thead-tr">
            <div></div>
            <div>星期一</div>
            <div>星期二</div>
            <div>星期三</div>
            <div>星期四</div>
            <div>星期五</div>
            <div>星期六</div>
            <div>星期日</div>
          </div>
          <div class="tbody-tr">
            <div>1</div>
            <div></div>
            <div>
              <span>文字</span>
            </div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div>
              <div class="card" data-x="3" data-y="0" style="height: 72px; width: 84px">星期四 1~3格</div>
            </div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>2</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>3</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>4</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>5</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>6</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>7</div>
            <div><span>文字</span></div>
            <div></div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>8</div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>9</div>
            <div><span>文字</span></div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>10</div>
            <div><span>文字</span></div>
            <div></div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>11</div>
            <div><span>文字</span></div>
            <div data-forbid="true">
              <span class="forbid">禁止放置</span>
            </div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
          <div class="tbody-tr">
            <div>12</div>
            <div><span>文字</span></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
          </div>
        </div>
    
  • JavaScript 代码

    //----------- 点击移动卡片 ------------------
    var $card = $('.week-table .card')
    var $weekTable = $('.week-table')
    var cardVerticalNumber = 3
    var xNumber = 7
    var yNumber = 12
    positionCard($card, $weekTable, cardVerticalNumber, xNumber, yNumber)
    
    function positionCard($card, $weekTable, cardVerticalNumber, xNumber, yNumber) {
      //--------  拖动卡片 --------
      var data = {}
      var tdHeight = 26 // 每一个 div 的高度
      var tdWidth = 88 // 每一个 div 的宽度
      var xNumber = xNumber // X 轴div数量,不含序列
      var yNumber = yNumber // Y轴div数量,不含星期列
      var xMoveMini = Math.floor(tdWidth / 4) // x轴最小移动距离,才开始计算方向
      var yMoveMini = Math.floor(tdHeight / 2) // y轴最小移动距离,才开始计算方向
      var cardHeight = $card.height()
      var cardWidth = $card.width()
      var cardVerticalNumber = cardVerticalNumber // 卡片占据的td数量
      var topLimit = 0 //顶部最大移动距离
      var bottomLimit = yNumber * tdHeight - cardHeight // 底部最大移动距离
      var leftLimit = 0 // 左边最大移动距离
      var rightLimit = xNumber * tdWidth - cardWidth // 右边最大移动距离
      var weekNameZh = ['一', '二', '三', '四', '五', '六', '日']
      $weekTable
        .find('.tbody-tr>div:not(:first-child)')
        .not('[data-forbid="true"]') // 要不要都行,isPutHere 也做了处理
        .on('click', function () {
          var $this = $(this)
          var xIndex = $this.index() - 1
          var yIndex = $this.parent().index() - 1
          var isPut = isPutHere(xIndex, yIndex)
          if (!isPut) return true
          data.newIndexX = xIndex
          data.newIndexY = yIndex
          moveCard(xIndex, yIndex, $this)
        })
    
      $card.mousedown(function (e) {
        var $this = $(this)
        var moveFlag = false // 防止别的事件触发
        data.oldIndexX = Number($this.attr('data-x'))
        data.oldIndexY = Number($this.attr('data-y'))
        data.left = e.pageX
        data.top = e.pageY
        data.sPositionX = data.oldIndexX * tdWidth
        data.sPositionY = data.oldIndexY * tdHeight
        var tempNewLeft = data.left // 上次移动时的位置信息,用于判断移动方向
        var tempNewTop = data.top // 上次移动时的位置信息,用于判断移动方向
        $(document).mousemove(function (e) {
          moveFlag = true
          data.newLeft = e.pageX
          data.newTop = e.pageY
          data.x = data.newLeft - data.left
          data.y = data.newTop - data.top
          data.newPositionX = data.sPositionX + data.x
          data.newPositionY = data.sPositionY + data.y
          var xMove = data.newLeft - tempNewLeft
          var yMove = data.newTop - tempNewTop
    
          // 元素没移动
          if (Math.abs(xMove) === 0 && Math.abs(yMove) === 0) return true
    
          if (data.newPositionX > rightLimit) {
            data.newPositionX = rightLimit
          }
    
          if (data.newPositionX < leftLimit) {
            data.newPositionX = leftLimit
          }
    
          if (data.newPositionY < topLimit) {
            data.newPositionY = topLimit
          }
    
          if (data.newPositionY > bottomLimit) {
            data.newPositionY = bottomLimit
          }
    
          // 当前移动,不超过一定距离不代表要移动
          if (Math.abs(xMove) > xMoveMini) {
            data.newIndexX = Math.ceil(data.x / tdWidth) + data.oldIndexX - 1
    
            // X index 的取值范围
            data.newIndexX = data.newIndexX <= 0 ? 0 : data.newIndexX
            data.newIndexX = data.newIndexX >= xNumber - 1 ? xNumber - 1 : data.newIndexX
          } else {
            data.newIndexX = data.oldIndexX
          }
    
          if (Math.abs(yMove) > yMoveMini) {
            data.newIndexY = Math.ceil(data.y / tdHeight) + data.oldIndexY - 1
    
            // Y index 的取值范围
            data.newIndexY = data.newIndexY <= 0 ? 0 : data.newIndexY
            data.newIndexY = data.newIndexY >= yNumber - cardVerticalNumber ? yNumber - cardVerticalNumber : data.newIndexY
          } else {
            data.newIndexY = data.oldIndexY
          }
    
          // 移动时,给将要移动到的地方一个高亮
          setHighlight(false, data.newIndexX, data.newIndexY)
    
          $card.css({
            left: data.newPositionX - data.sPositionX + 'px',
            top: data.newPositionY - data.sPositionY + 'px'
          })
        })
    
        $(document).mouseup(function (e) {
          // 下面这句话放在  if (!moveFlag) return 后面,会导致点击卡片,卡片随着鼠标指针移动
          $(document).off('mousemove')
          if (!moveFlag) return
          moveFlag = false
          tempNewLeft = data.newLeft
          tempNewTop = data.newTop
    
          setHighlight(true, data.newIndexX, data.newIndexY)
          $card.css({
            top: '1px',
            left: '1px'
          })
    
          // 不允许放置,放到上一个可用的位置
          if (isPutHere(data.newIndexX, data.newIndexY)) {
            moveCard(data.newIndexX, data.newIndexY)
          } else {
            moveCard(data.tempIndexX, data.tempIndexY)
          }
        })
      })
    
      function moveCard(x, y, $target) {
        setCardIndex(x, y)
        setCardInfo(x, y)
        var $parent = $target ? $target : getParent(x, y)
        $parent.append($card)
      }
    
      // 判断是否当前位置是否可放置
      function isPutHere(newX, newY) {
        var isPut = true
        // 当前 Y 轴 加上卡片高度超出Y 轴则直接返回 false
        if (newY + cardVerticalNumber > yNumber) return false
        for (var i = 0; i < cardVerticalNumber; i++) {
          var $parent = getParent(newX, newY + i)
          // 不允许放置的位置,高亮上一个可用的位置
          if ($parent.length <= 0 || isTdForbid($parent)) {
            isPut = false
          }
        }
    
        return isPut
      }
    
      function setHighlight(isRemoveClass, newX, newY) {
        $weekTable.find('.tbody-tr div').removeClass('highlight')
    
        var isPut = isPutHere(newX, newY)
        if (isPut) {
          // 存储上一个可用的位置
          data.tempIndexX = newX
          data.tempIndexY = newY
        }
    
        if (!isRemoveClass) {
          // 判断当前位置是否有禁用的 td
          for (var i = 0; i < cardVerticalNumber; i++) {
            if (isPut) {
              $parent = getParent(newX, newY + i)
            } else {
              $parent = getParent(data.tempIndexX, data.tempIndexY + i)
            }
            $parent.addClass('highlight')
          }
        }
      }
    
      function getParent(x, y) {
        return $weekTable
          .find('.tbody-tr')
          .eq(y)
          .find('>div')
          .eq(x + 1)
      }
    
      function isTdForbid($el) {
        return $el.attr('data-forbid')
      }
    
      function setCardIndex(x, y) {
        $card.attr('data-x', x)
        $card.attr('data-y', y)
      }
    
      function setCardInfo(x, y) {
        var dayName = weekNameZh[x]
        $card.text(`星期${dayName} ${y + 1}~${y + cardVerticalNumber}`)
      }
    }
    
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用JavaScriptCSS实现左右滑动的表格示例: ```html <!DOCTYPE html> <html> <head> <title>可左右拖动表格</title> <style> .table-wrapper { overflow-x: auto; white-space: nowrap; } table { border-collapse: collapse; width: 100%; } th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; } th { background-color: #f2f2f2; } </style> </head> <body> <div class="table-wrapper"> <table> <thead> <tr> <th>姓名</th> <th>年龄</th> <th>性别</th> <th>城市</th> <th>学历</th> </tr> </thead> <tbody> <tr> <td>张三</td> <td>25</td> <td>男</td> <td>北京</td> <td>本科</td> </tr> <tr> <td>李四</td> <td>30</td> <td>女</td> <td>上海</td> <td>硕士</td> </tr> <tr> <td>王五</td> <td>28</td> <td>男</td> <td>广州</td> <td>本科</td> </tr> <tr> <td>赵六</td> <td>35</td> <td>女</td> <td>深圳</td> <td>博士</td> </tr> </tbody> </table> </div> <script> // 获取表格包裹器和表格 var tableWrapper = document.querySelector('.table-wrapper'); var table = document.querySelector('table'); // 当鼠标在表格上按下时记录位置 var isDown = false; var startX; var scrollLeft; tableWrapper.addEventListener('mousedown', function(e) { isDown = true; startX = e.pageX - tableWrapper.offsetLeft; scrollLeft = tableWrapper.scrollLeft; }); // 当鼠标移动拖动表格 tableWrapper.addEventListener('mousemove', function(e) { if (!isDown) return; e.preventDefault(); var x = e.pageX - tableWrapper.offsetLeft; var walk = (x - startX) * 3; tableWrapper.scrollLeft = scrollLeft - walk; }); // 当鼠标松开时停止拖动 tableWrapper.addEventListener('mouseup', function() { isDown = false; }); // 当鼠标离开表格时停止拖动 tableWrapper.addEventListener('mouseleave', function() { isDown = false; }); </script> </body> </html> ``` 在这个示例,我们首先创建了一个table-wrapper类的div元素,用于包裹表格。然后在CSS设置了表格单元格的样式,并将table-wrapper元素的overflow-x属性设置为auto,以便在表格宽度超出容器宽度时显示水平滚动条。 接下来,我们使用JavaScript监听table-wrapper元素上的mousedown、mousemove和mouseup事件。当按下鼠标时,我们记录当前鼠标位置和表格包裹器的scrollLeft值。然后在鼠标移动时,我们计算出鼠标相对于起始位置的偏移量,将其乘以一个常数(3)并将结果减去初始的scrollLeft值,以获得新的scrollLeft值。最后,在鼠标松开或离开表格时,我们停止拖动。 这样就可以实现一个可以左右丝滑拖动表格
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值