js拖拽排序功能

<!DOCTYPE html>
<html>
<head>
<title>拖拽排序</title>
<style>
  #container {
    display: flex;
  }

  .item {
    width: 100px;
    height: 50px;
    background-color: lightblue;
    margin: 10px;
    text-align: center;
    line-height: 50px;
    cursor: move;
    user-select: none; /* 防止拖拽时选中文字 */
  }

  .dragging {
    opacity: 0.5;
  }

  .over {
    background-color: lightgreen;
  }
</style>
</head>
<body>

<div id="container">
  <div class="item" draggable="true">Item 1</div>
  <div class="item" draggable="true">Item 2</div>
  <div class="item" draggable="true">Item 3</div>
</div>

<script>
  const container = document.getElementById('container');
  const items = document.querySelectorAll('.item');

  let draggedItem = null;

  items.forEach(item => {
    item.addEventListener('dragstart', (e) => {
      draggedItem = item;
      item.classList.add('dragging');
      e.dataTransfer.effectAllowed = 'move'; // 设置允许的操作为移动
      e.dataTransfer.setData('text/plain', null); //  这行对于 Firefox 很重要
    });

    item.addEventListener('dragend', () => {
      draggedItem.classList.remove('dragging');
      items.forEach(item => item.classList.remove('over')); // 清除所有 over 样式
      draggedItem = null;
    });

    item.addEventListener('dragover', (e) => {
      e.preventDefault(); //  必须preventDefault(),否则drop事件不会触发
      e.dataTransfer.dropEffect = 'move'; //  视觉反馈
      const target = e.target.closest('.item'); // 确保目标是.item元素

      if (target && target !== draggedItem) {
        const rect = target.getBoundingClientRect();
        const offsetY = e.clientY - rect.top;
        const targetCenter = rect.height / 2;

        if (offsetY < targetCenter) {
          container.insertBefore(draggedItem, target);
        } else {
          container.insertBefore(draggedItem, target.nextSibling);
        }
        items.forEach(item => item.classList.remove('over')); // 清除之前的 over 样式
        target.classList.add('over');
      }
    });

    item.addEventListener('dragenter', (e) => {
      const target = e.target.closest('.item');
      if (target && target !== draggedItem) {
          target.classList.add('over');
      }
    });

    item.addEventListener('dragleave', (e) => {
      const target = e.target.closest('.item');
      if (target) {
          target.classList.remove('over');
      }
    });


    item.addEventListener('drop', (e) => {
      e.preventDefault(); // 阻止默认行为
    });
  });
</script>

</body>
</html>

关键步骤和代码解释:

  1. 设置draggable属性: 在需要拖拽的元素上设置 draggable="true"

  2. dragstart事件: 当开始拖拽元素时触发。在这个事件中,记录被拖拽的元素,并设置拖拽数据和效果。e.dataTransfer.setData('text/plain', null); 对于 Firefox 正常工作至关重要,即使你不需要传输任何数据。

  3. dragend事件: 拖拽结束时触发。清除拖拽相关的样式和变量。

  4. dragover事件: 当拖拽的元素在目标元素上方时触发。必须调用 e.preventDefault() 才能触发 drop 事件。此事件用于处理元素插入位置的逻辑。 通过计算鼠标相对于目标元素中心的位置来确定插入位置。

  5. dragenter 和 dragleave 事件: 用于添加和移除目标元素的 hover 样式,提供视觉反馈。使用 `closest

vuedraggable拖拽排序插件:

<template>
    <div style="border: 1px solid #e8e8e8;width: 300px;">
        <draggable v-model="reportList" @end="endEvent" v-bind="dragOptions">
            <p v-for="r in reportList" :key="r.id" :class="r.active ? 'active' : 'disabled'">{
  
  {r.name}}</p>
        </draggable>
    </div>
</template>
<script>
import draggable from "vuedraggable"
export default {
    components: {
        draggable
    },
    data () {
        return {
            dragOptions: {
                animation: 500,
                filter: '.disabled'
            },
            reportList: [
                { id: 1, name: 'javascript', active: true},
                { id: 2, active: false, name:'css' },
                { id: 3, active: false, name: 'typescript' },
                { id: 4, active: false, name: 'vue.js' },
                { id: 5, active: false, name: 'nodejs' }
            ]
        }
    },
    methods: {
        endEvent () {
            console.log(this.reportList) // 自动更新reportList
        }
    }
}
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值