利用sortablejs实现拖拽列表组件

1,484 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第24天,点击查看活动详情

🎉前言

本篇文章是我对拖拽列表功能的一些理解,实现一个简单的拖拽组件,来巩固一些知识点,如果能帮助到大家就更好😄

⭐️ ​组件基本架构

vue 项目中 使用 npm install --seve sortablejs 安装插件。

sortablejs 官网

👨 ​父组件

接收一个 props 数组参数,用来记录 列表的条数,默认插槽 slot 用来存放 列表项

// drag-wrap-test.vue
<template>
<div class="jc-drag-wrap-test" ref="wrapTest">
  <slot></slot>
</div>
</template>
​
<script>
export default {
  name: "jcDragWrapTest",
  props: {
    data: {
      type: Array,
      default: () => []
    }
  },
  data () {
    return {
      list: []
    }
  }
};
</script>

👶 ​子组件

默认插槽 slot 用来存放 传进来的数据。CSS样式写好。

// drag-test-item.vue
<template>
<div class="jc-drag-test-item">
  <span><slot></slot></span>
  <p>view on Behance</p>
</div>
</template>
​
<script>
export default {
  name: "jcDragTestItem",
};
</script>
​
<style lang="scss" scoped>
.jc-drag-test-item{
  // ...样式代码省略
}
</style>

👪 ​实现效果

// 使用组件
<template>
<div>
    <drag :data="tableData">
        <drag-item v-for="item in tableData" :key="item.address">
            {{ item.address }}
        </drag-item>
    </drag>
</div>
</template>
<script>
import drag from './drag-wrap-test/src/drag-wrap-test';
import dragItem from './drag-wrap-test/src/drag-test-item';
export default {
  name: 'HelloWorld',
  components: {
    drag,
    dragItem
  },
  data () {
    return {
      tableData: [
        {
          address: '深圳市南山区西丽 5 号线'
        },
        {
          address: '深圳市南山区西丽 6 号线'
        },
        {
          address: '深圳市南山区西丽 7 号线'
        },
        {
          address: '深圳市南山区西丽 8 号线'
        }
      ]
    }
  }
}
</script>

GIF 2022-4-25 0-14-53.gif

💫 ​实现拖拽

上述代码实现只是把基本样子写好,但是没有拖拽的功能,那我们借助 sortablejs 插件来试一下吧。

主要是在父组件里的实现:

// drag-wrap-test.vue
<template>
    // ...省略代码
</template>
​
<script>
import { Sortable } from 'sortablejs';
export default {
    // ...省略代码
    mounted () {
        let vm = this;
        this.list = this.data;
        // 调用Sortable 创建实例,传入两个参数(父元素,{配置项})
        // 通过获取父元素的DOM,给里面的每个子元素添加配置项。
        Sortable.create(this.$refs.wrapTest,{
            animation: 150, // 过度效果,定义排序动画的时间
        })
    }
};
</script>

GIF 2022-4-25 0-27-30.gif

可以看到,拖拽的效果实现了,完结撒花~~ ✿✿ヽ(°▽°)ノ✿

但是这里有个问题,拖拽之后,如果页面刷新后,就会回到默认状态,怎么办?

那我们可以尝试给组件添加一个监听事件,如果你拖拽了列表,就会触发一个函数。

👀 拖拽事件监听

主要是利用 Sortablejs 里的 onEed()拖拽结束时触发的函数。

Sortable.create(this.$refs.wrapTest,{
    animation: 150, // 过度效果,定义排序动画的时间
    onEnd (event) {
        vm.list = vm.data;
        vm.list.splice(event.newIndex, 0, vm.list.splice(event.oldIndex, 1)[0]);
        let newArr = vm.list.splice(0);
        vm.list = [];
        vm.$nextTick(() => {
          vm.$emit('watchData', newArr);
        })
    }
})

onEnd() 函数中的 event 里面有被拖拽的列表项的一些监听属性,其实就是通过获取拖拽结束后新的数组,然后利用 $emit 事件把新的数组向父组件传递出去,在使用组件时,把新的数组重新赋值给 tableData 就好了。

修改一下 实现效果 中的代码:

<template>
<div>
    <drag :data="tableData" @watchData="watchData">
        <drag-item v-for="item in tableData" :key="item.address">
            {{ item.address }}
        </drag-item>
    </drag>
</div>
</template>
<script>
export default {
    name: 'HelloWorld',
    // ...省略代码  
    methods: {
    watchData (data) {
      console.log(data);
      this.tableData = data;
    }
  }
}
</script>

我们来看一下最终的实现效果:

GIF 2022-4-25 1-01-20.gif

一个基本的拖拽列表组件就完成了~~ 真 · 完结撒花✿✿ヽ(°▽°)ノ✿

其实还有许多问题是没有考虑进去的,比如从这个列表拖拽到别的列表中呀,横向的拖拽呀等等,相信大家也能够自己实现,小弟我就不在这里班门弄斧了~~ 😙

👉 演示的源代码在这里 Gitee 链接。

✨总结

总的来说,实现该组件较为简单,比较麻烦的是,怎么拿到拖拽结束后新的数组列表。对于更为复杂的场景,我也是在慢慢探索呢。

以上我本次分享的全部内容~~

如果觉得文章写得不错,对你有所启发的,请不要吝啬 点个 关注 并在 评论区 留下你宝贵的意见哦~~😃