Vue3 组件拖动

效果

 前文

本文使用的是Vue3 + TS ,请酌情参考。

插件

sortablejs
@types/sortablejs

代码 

<template>
  <div class="drag-test-page">
    <!--  vue3  TransitionGroup 组件  https://cn.vuejs.org/guide/built-ins/transition-group.html-->
    <TransitionGroup name="drag-tes-list">
      <!--   盒子容器   -->
      <div class="box" v-for="(item,index) in dataList" :key="item">
        <!--    盒子 为啥在这写含有动画样式的类 因为在外边那一层写动画样式会影响Sortable的效果    -->
        <div class="box-content" :class="{'drag':isDrag}">
          {{ item }}
          <!--     删除按钮     -->
          <div class="box-btn" v-if="isDrag" @click="removeBox(index)">
            <span class="iconfont icon-close"></span>
          </div>
        </div>
      </div>
    </TransitionGroup>
  </div>
  <nut-button @click="edit" style="margin: 10px">{{ isDrag ? '保存' : '编辑' }}</nut-button>
</template>

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

// 列表数据
const dataList = ref<Array<number>>([])
// 是否数据拖动状态
const isDrag = ref(false)
// 拖动组件
let sortable: Sortable | null = null

// 编辑
function edit () {
  isDrag.value = !isDrag.value
  if (isDrag.value) {
    createSortable()
  } else {
    sortable?.destroy()
  }
}

// 删除元素
function removeBox (index: number) {
  dataList.value.splice(index, 1)
}

// 创建拖动组件
function createSortable () {
  const parentDom: HTMLElement | null = document.querySelector('.drag-test-page')
  if (parentDom) {
    sortable = Sortable.create(parentDom, {
      // 动画时间
      animation: 200,
      // 延迟拖动时间,100ms以内算点击 100ms以后算拖动,以此来区分是点击还是拖动
      delay: 100,
      // 拖动结束
      onEnd: (event) => {
        // 移动之后改变数据
        if (event.oldIndex !== undefined && event.newIndex !== undefined) {
          const element = dataList.value.splice(event.oldIndex, 1)
          dataList.value.splice(event.newIndex, 0, element[0])
        }
      }
    })
  }
}

onMounted(() => {
  // 初始化数据
  for (let i = 0; i < 10; i++) {
    dataList.value.push(i)
  }
})
</script>

<style lang="scss">
// 颤动动画
@keyframes shake {
  0% {
    transform: rotateZ(-2deg);
  }
  100% {
    transform: rotateZ(2deg);
  }
}

.drag-test-page {
  display: flex;
  flex-wrap: wrap;

  .box {
    width: 100px;
    height: 100px;
    margin: 20px;

    .box-content {
      width: 100%;
      height: 100%;
      background: #0287FF;
      border-radius: 8px;
      color: white;
      display: flex;
      align-items: center;
      justify-content: center;
      position: relative;

      // 颤动动画
      &.drag {
        animation-name: shake;
        animation-duration: 0.12s;
        animation-iteration-count: infinite;
        animation-direction: alternate;
        animation-timing-function: linear;
      }

      .box-btn {
        width: 30px;
        height: 30px;
        line-height: 1;
        background: #fc5346;
        border-radius: 50%;
        position: absolute;
        left: 0;
        top: 0;
        transform: translate(-30%, -30%);
        display: flex;
        align-items: center;
        justify-content: center;

        .iconfont {
          font-size: 25px;
        }

      }
    }
  }

  // 列表动画
  .drag-tes-list-move,
  .drag-tes-list-enter-active,
  .drag-tes-list-leave-active {
    transition: all 0.36s ease;
  }

  .drag-tes-list-enter-from,
  .drag-tes-list-leave-to {
    opacity: 0;
  }
}
</style>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值