- 基于 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 moveFlag = false $(document).off('mousemove') 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}格`) } }