<div>
  <h1>课程表</h1>
  <div class="container">
    <div class="left" data-drop="move">
      <ul>
        <li>
          <div data-effect="copy" draggable="true" class="subject chinese">语文</div>
        </li>
        <li>
          <div data-effect="copy" draggable="true" class="subject maths">数学</div>
        </li>
        <li>
          <div data-effect="copy" draggable="true" class="subject english">英语</div>
        </li>
        <li>
          <div data-effect="copy" draggable="true" class="subject physics">物理</div>
        </li>
        <li>
          <div data-effect="copy" draggable="true" class="subject chemistry">化学</div>
        </li>
        <li>
          <div data-effect="copy" draggable="true" class="subject organism">生物</div>
        </li>
        <li>
          <div data-effect="copy" draggable="true" class="subject sport">体育</div>
        </li>
      </ul>
    </div>
    <div class="right" data-drop="remove">
      <table>
        <!-- 列的分组 -->
        <colgroup>
          <col>
          <col>
          <col>
          <col>
          <col>
          <col>
          <col>
          <col>
        </colgroup>
        <thead>
          <tr>
            <td></td>
            <th>星期一</th>
            <th>星期二</th>
            <th>星期三</th>
            <th>星期四</th>
            <th>星期五</th>
            <th>星期六</th>
            <th>星期日</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td class="span" rowspan="4">上午</td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
          </tr>
          <tr>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
          </tr>
          <tr>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
          </tr>
          <tr>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
          </tr>
          <tr class="divide"></tr>
          <tr>
            <td class="span" rowspan="3">下午</t>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
          </tr>
          <tr>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
          </tr>
          <tr>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
            <td data-drop="copy"></td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</div>
* {
  box-sizing: border-box;
}
h1 {
  text-align: center;
}
.container {
  display: flex;
  gap: 10px;
}
.left,
.right {
  background: #fbfbfb;
}
.right {
  flex: 1;
}
ul,
li {
  margin: 0;
  padding: 0;
  list-style: none;
}
ul {
  padding: 10px;
}
li {
  margin-bottom: 10px;
}
li:last-child {
  margin-bottom: 0;
}
.subject {
  padding: 8px 15px;
  color: #fff;
  font-size: 16px;
  font-weight: 500;
  border-radius: 2px;
  min-height: 0;
  min-width: 65px;
  text-align: center;
}
.chinese {
  background: #ff4c4c;
}
.maths {
  background: #0abf53;
}
.english {
  background: #f47721;
}
.physics {
  background: #0099e5;
}
.chemistry {
  background: #d20962;
}
.organism {
  background: #7d3f98;
}
.sport {
  background: #8a7967;
}
.right {
  padding: 10px;
}
table {
  width: 100%;
  border: none;
  border-spacing: 1px;
}
tr.divide {
  height: 40px;
}
th,
td {
  min-width: 80px;
  min-height: 40px;
  padding: 10px 15px;
  text-align: center;
  background: #caccd1;
  border-radius: 2px;
  border: 1px solid #9f9fa3;
}
thead td {
  background: inherit;
  min-width: 0;
  min-height: 0;
  width: 10px;
  border: none;
}
tbody td {
  height: 50px;
  background: inherit;
}
.span {
  min-width: 0;
  min-height: 0;
  padding: 10px;
  font-weight: bold;
  background: #caccd1;
  border: 1px solid #9f9fa3;
}
.drag-highlight {
  background: #c4dff6;
}
// 找到父元素进行事件委托
const container = document.querySelector(".container");
let source; // 用来保存被拖拽元素的节点
// 开始事件
container.addEventListener("dragstart", function (e) {
  source = e.target;
  e.dataTransfer.effectAllowed = e.target.dataset.effect;
});
// 移动事件
container.addEventListener("dragover", function (e) {
  e.preventDefault();
});
// 进入事件
container.addEventListener("dragenter", function (e) {
  clearDropStyle();
  // 只有携带 data-drop 属性的节点才有高亮提示
  const dropNode = getDropNode(e.target);
  if (dropNode && dropNode.dataset.drop === e.dataTransfer.effectAllowed) {
    dropNode.classList.add("drag-highlight");
  }
});
// 释放事件
container.addEventListener("drop", function (e) {
  clearDropStyle();
  const dropNode = getDropNode(e.target);
  if (dropNode && dropNode.dataset.drop === "remove") {
    source.remove();
    return;
  }
  if (dropNode && dropNode.dataset.drop === e.dataTransfer.effectAllowed) {
    // 复制的情况
    if (dropNode.dataset.drop === "copy") {
      // 清除掉之前的节点,防止重复
      dropNode.innerHTML = "";
      const cloned = source.cloneNode(true);
      cloned.dataset.effect = "move";
      dropNode.appendChild(cloned);
    } else {
      // 移动的情况
      source.remove();
    }
  }
});
// 清楚掉之前的高亮样式
function clearDropStyle() {
  document.querySelectorAll(".drag-highlight").forEach((node) => {
    node.classList.remove("drag-highlight");
  });
}
// 找到带有 data-drop 属性的节点
function getDropNode(node) {
  while (node) {
    if (node.dataset?.drop) return node;
    node = node.parentNode;
  }
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.