Skip to content

拖拽API

更新: 2025/3/23 21:32:41

课程表

语文
数学
英语
音乐
政治
历史
体育
星期一星期二星期三星期四星期五星期六星期日
上午
下午
html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>定制课程表</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <h1>课程表</h1>
    <div class="container">
      <div class="left" data-drop="move">
        <!-- draggable设置为true就可以实现拖拽 -->
        <div data-effect="copy" draggable="true" class="color1 item">语文</div>
        <div data-effect="copy" draggable="true" class="color2 item">数学</div>
        <div data-effect="copy" draggable="true" class="color3 item">英语</div>
        <div data-effect="copy" draggable="true" class="color4 item">音乐</div>
        <div data-effect="copy" draggable="true" class="color5 item">政治</div>
        <div data-effect="copy" draggable="true" class="color6 item">历史</div>
        <div data-effect="copy" draggable="true" class="color7 item">体育</div>
      </div>
      <div class="right">
        <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>
              <th rowspan="4" class="span">上午</th>
              <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>
              <td colspan="8" class="noborder"></td>
            </tr>

            <tr>
              <th rowspan="4" class="span">下午</th>
              <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>
          </tbody>
        </table>
      </div>
    </div>

    <script src="./index.js"></script>

  </body>
</html>
js
// 这里我们使用事件委托来在父元素上注册事件
const container = document.querySelector(".container");

let source;

// 只触发一次,事件源e是拖动的那个元素
container.ondragstart = (e) => {
  e.dataTransfer.effectAllowed = e.target.dataset.effect; //设置鼠标样式,我们自定义一个属性,用来表示是拖进(copy)还是拖出(move)
  source = e.target;
};

//会不断触发,事件源e是放置位置的元素
container.ondragover = (e) => {
  e.preventDefault(); // 阻止默认事件,因为div等是不允许元素有元素放置其上的
  // console.log('over', e.target);
};

function clearDropStyle() {
  document.querySelectorAll(".drop-over").forEach((node) => {
    node.classList.remove("drop-over");
  });
}
// 看背景颜色是否变化,不仅要看自身,也要看父元素
function getDropNode(node) {
  while (node) {
    if (node.dataset && node.dataset.drop) {
      return node;
    }
    node = node.parentNode;
  }
}

// 和ondragover很像,但是不会触发的很频繁,e指的是进入的元素
container.ondragenter = (e) => {
  // 清除之前的drop-over
  clearDropStyle();
  const dropNode = getDropNode(e.target);
  if (dropNode && dropNode.dataset.drop === e.dataTransfer.effectAllowed) {
    // 该节点能够接受目前拖拽的节点
    dropNode.classList.add("drop-over");
  }
};

// 拖拽放手的事件
container.ondrop = (e) => {
  clearDropStyle();
  const dropNode = getDropNode(e.target);
  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 {
      // move
      source.remove();
    }
  }
};

//e是离开的元素
container.ondragleave = (e) => {
  console.log("leave", e.target);
};
css
.container {
  display: flex;
  justify-content: center;
}

.container .left {
  padding: 10px;
  width: 80px;
  background: #eee;
}

.container .left .item {
  margin-bottom: 10px;
}

.item {
  width: 100%;
  line-height: 40px;
  text-align: center;
  cursor: move;
}

.color1 {
  background: #f26395;
}

.color2 {
  background: #62efab;
}

.color3 {
  background: #ef7658;
}

.color4 {
  background: #ffe868;
}

.color5 {
  background: #80e3f7;
}

.color6 {
  background: #d781f9;
}

.color7 {
  background: #62efab;
}

.container .right {
  background: #eee;
  width: 800px;
  margin-left: 10px;
  padding: 10px;
}

.container .right table {
  width: 100%;
}

.container .right td,
.container .right th {
  border: 1px solid #999;
  height: 33px;
  padding: 8px;
  text-align: center;
}

.container .right col:first-child {
  width: 40px;
}

.container .right .span {
  line-height: 40px;
}

.container .right thead td:first-child,
.container .right .noborder {
  border: none;
}

.container .right th {
  font-weight: normal;
  background: #ccc;
}

.container .drop-over {
  background: #666;
}