vue3 实现拖拽排序效果 sortablejs

效果图

 依赖安装

npm i sortablejs -S
<template>
  <div class="warp">
    <div class="parent-box" v-for="pItem in sortData" :key="pItem.name">
      <h2 class="parent-name">{{ pItem.name }}</h2>
      <div class="child-list" >
        <div class="child-box" v-for="(cItem, cIndex) in pItem.children" :key="cItem.name" :data-id="cIndex">
          <div class="child-name">{{ cItem.name }}</div>
        </div>
      </div>
    </div>
  </div>
  <br>
  <div>
    <div> {{ sortData[0].name }}</div>
    <br>
    <div> {{ sortData[0].children }}</div>
  </div>
  <br>
  <div>
    <div> {{ sortData[1].name }}</div>
    <br>
    <div> {{ sortData[1].children }}</div>
  </div>
  <br>
  <div>
    <div> {{ sortData[2].name }}</div>
    <br>
    <div> {{ sortData[2].children }}</div>
  </div>

</template>

<script setup lang="ts">
import Sortable from 'sortablejs'
import { ref, onMounted, nextTick } from 'vue'

interface DropEndType {
  newIndex: number
  oldIndex: number
}

interface ParentDropEndType extends DropEndType {
  item: { closest: (arg0: string) => Element }
}

const sortData = ref([
  {
    name: 'Parent 1',
    children: [
      { name: 'child 1 - P1' },
      { name: 'child 2 - P1' },
      { name: 'child 3 - P1' },
      { name: 'child 4 - P1' }
    ]
  },
  {
    name: 'Parent 2',
    children: [
      { name: 'child 1 - P2' },
      { name: 'child 2 - P2' },
      { name: 'child 3 - P2' },
      { name: 'child 4 - P2' }
    ]
  },
  {
    name: 'Parent 3',
    children: [
      { name: 'child 1 - P3' },
      { name: 'child 2 - P3' },
      { name: 'child 3 - P3' },
      { name: 'child 4 - P3' }
    ]
  }
])

onMounted(() => {
  const parentContainers = document.querySelectorAll('.parent-box')

  parentContainers.forEach((container, index) => {
    new Sortable(container.querySelector('.child-list'), {
      group: `parent-${index}`,
      sort: true,
      animation: 150,
      ghostClass: 'sortable-ghost',
      onEnd: (e:ParentDropEndType) => {
        nextTick(() => {
          const allParentDom = document.querySelectorAll('.parent-box')
          const parentIndex = Array.from(allParentDom).indexOf(e.item.closest('.parent-box'))
          const childIndex = e.newIndex
          const targetRow = sortData.value[parentIndex].children.splice(e.oldIndex, 1)[0]
          sortData.value[parentIndex].children.splice(childIndex, 0, targetRow)

          console.log(sortData.value)
        })
      }
    })
  })

  new Sortable(document.querySelector('.warp'), {
    group: 'parent',
    sort: true,
    animation: 300,
    ghostClass: 'sortable-ghost',
    onEnd: (e:DropEndType) => {
      nextTick(() => {
        const targetRow = sortData.value.splice(e.oldIndex, 1)[0]
        sortData.value.splice(e.newIndex, 0, targetRow)
        console.log(sortData.value)
      })
    }
  })
})
</script>
<style lang="scss" scoped>
h2 {
  margin: 0;
}
.warp {
  background-color: #fff;
  margin-top: 20px;
  line-height: 1;
  .parent-name {
    padding: 10px;
    background-color: #ddd;
    margin-top: 20px;
    cursor: move;
  }
  .child-list {
    .child-name {
      background-color: #f4f1f1;
      padding: 15px 20px;
      margin-top: 5px;
      cursor: move;
    }
  }
}
</style>


如果需要ts

npm i --save-dev @types/sortablejs 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值