使用H5的
draggable="true"
虽然可以实现拖拽,但如果是在vue中使用,我们需要去封装,虽然不难,但是有成熟的轮子为什么不用呢?
在vue中实现拖拽可以使用
vuedraggable
实现。
在vue2中的使用有一堆文章,但是在vue3中的使用还是比较少,这里使用vue3进行演示
插件仓库地址:
vuedraggable
yarn add vuedraggable@next
npm i -S vuedraggable@next
import draggable from 'vuedraggable'
使用<draggable>
标签
属性 v-model="List"
这个List为一个数组,一般与实际数据对应。排序、拖拽实际上都是改变这个List的值或顺序。
属性 item-key="key"
这个key为每个可拖拽组件的key,要求List数组中的每个数据项中有一个key作为子组件的唯一标识。
属性 group 分组,如果要在不同容器间实现拖拽,那么它们的组名应该相等,例如:group=‘people’。
但其中有几个属性:
name: 组名
pull 拖动的时候
put 放置的时候
:group="{ name: 'course', pull: 'clone', put: true }"
属性 tag 渲染后的<draggable>
,例如tag =‘span’,那么<draggable>
就会变为<span>
事件start
, add
,remove
,update
,end
,choose
,unchoose
,sort
,filter
,clone
更多的请看官方文档...
3.1 拖拽排序
<template>
<div class="like">
likeList数据列表
item-key数据项中某个属性作为key
<draggable v-model="likeList" item-key="id">
<template #item="{ element }">
<div class="item">{{ element.id + "、" + element.name }}</div>
</template>
</draggable>
</div>
{{ likeList }}
</template>
<script>
import { defineComponent, ref } from "vue";
import draggable from "vuedraggable";
export default defineComponent({
components: { draggable },
setup() {
const likeList = ref([
{ id: 1, name: "java程序设计基础" },
{ id: 2, name: "数据结构与算法" },
{ id: 3, name: "数据库原理" },
{ id: 4, name: "软件工程" },
return { likeList };
</script>
<style>
.item {
margin: 10px;
padding: 10px;
background: #ffffff;
.like {
background: #fbc531;
margin-bottom: 10px;
padding: 10px;
height: 300px;
</style>
3.2数据移动
<template>
<div class="like">
注意需要加上group属性,才能在两个容器中进行拖拽
<draggable v-model="likeList" item-key="id" group="course">
<template #item="{ element }">
<div class="item">{{ element.id + "、" + element.name }}</div>
</template>
</draggable>
</div>
<div class="unlike">
<draggable v-model="unlikeList" item-key="id" group="course">
<template #item="{ element }">
<div class="item">{{ element.id + "、" + element.name }}</div>
</template>
</draggable>
</div>
{{ likeList }}
{{ unlikeList }}
</template>
<script>
import { defineComponent, ref } from "vue";
import draggable from "vuedraggable";
export default defineComponent({
components: { draggable },
setup() {
const likeList = ref([
{ id: 1, name: "java程序设计基础" },
{ id: 2, name: "数据结构与算法" },
{ id: 3, name: "数据库原理" },
{ id: 4, name: "软件工程" },
const unlikeList = ref([
{ id: 5, name: "财务管理" },
{ id: 6, name: "会计" },
{ id: 7, name: "人力资源管理" },
{ id: 8, name: "企业管理" },
return { likeList, unlikeList };
</script>
<style lang="less">
.item {
margin: 10px;
padding: 10px;
background: #ffffff;
.like {
background: #fbc531;
margin-bottom: 10px;
padding: 10px;
height: 300px;
.unlike {
background: #353b48;
margin-bottom: 10px;
padding: 10px;
height: 300px;
</style>
3.3 数据克隆
有时候我们拖动的时候并不想影响原来的数据。
<template>
<div class="like">
注意需要加上group属性,并配置pull: 'clone'才能进行克隆
<draggable
v-model="likeList"
item-key="id"
:group="{ name: 'course', pull: 'clone' }"
<template #item="{ element }">
<div class="item">{{ element.id + "、" + element.name }}</div>
</template>
</draggable>
</div>
<div class="unlike">
<draggable
v-model="unlikeList"
item-key="id"
:group="{ name: 'course', pull: 'clone' }"
<template #item="{ element }">
<div class="item">{{ element.id + "、" + element.name }}</div>
</template>
</draggable>
</div>
{{ likeList }}
{{ unlikeList }}
</template>
<script>
import { defineComponent, ref } from "vue";
import draggable from "vuedraggable";
export default defineComponent({
components: { draggable },
setup() {
const likeList = ref([
{ id: 1, name: "java程序设计基础" },
{ id: 2, name: "数据结构与算法" },
{ id: 3, name: "数据库原理" },
{ id: 4, name: "软件工程" },
{ id: 5, name: "财务管理" },
{ id: 6, name: "会计" },
{ id: 7, name: "人力资源管理" },
const unlikeList = ref([{ id: 8, name: "企业管理" }]);
return { likeList, unlikeList };
</script>
<style">
.item {
margin: 10px;
padding: 10px;
background: #ffffff;
.like {
background: #fbc531;
margin-bottom: 10px;
padding: 10px;
.unlike {
background: #353b48;
margin-bottom: 10px;
padding: 10px;
</style>
3.4 与组件库配合
表单拖拽?
这里以ant-design-vue
作为例子,如何安装不演示,请看官网:next.antdv.com
这里我创建两个组件,一个为组件列表List,一个为待放置容器Content。
List:
<template>
pull: 'clone', put: false
意思是以克隆的方式拖拽,,不能在组件列表进行放置,目的是不影响原来的组件列表
<draggable
v-model="componentList"
item-key="id"
:group="{ name: 'component', pull: 'clone', put: false }"
<template #item="{ element }">
<div class="item">
{{ element.tag }}
</div>
</template>
</draggable>
</template>
<script>
import { defineComponent, ref } from "vue";
import draggable from "vuedraggable";
export default defineComponent({
name: "Lsit",
components: {
draggable,
setup() {
const componentList = ref([
id: 1,
tag: "a-button",
props: {
type: "primary",
id: 2,
tag: "a-empty",
props: {
description: "没有数据捏",
id: 3,
tag: "a-spin",
return {
componentList,
</script>
<style>
.item {
border: #0083ee 1px solid;
margin: 10px;
padding: 10px;
</style>
Content:
<template>
<draggable
v-model="componentList"
item-key="id"
class="content"
:group="{ name: 'component' }"
组件点击后,修改样式为激活状态
<template #item="{ element }">
:class="avtive == element.tag ? 'item-content active' : 'item-content'"
@click="avtive = element.tag"
使用vue的动态组件component 需要绑定一个is指明是哪个标签,is里面是标签名
使用v-bind绑定这个组件的属性(传入一个对象即可)
v-on使用v-on绑定这个组件对应的事件即可
<component
:is="element.tag"
v-bind="element.props"
v-on="element.event"
>{{ element.tag == "a-button" ? "a-button" : "" }}</component
</div>
</template>
</draggable>
</template>
<script>
import { defineComponent, ref } from "vue";
import draggable from "vuedraggable";
export default defineComponent({
components: { draggable },
setup() {
const avtive = ref("");
const componentList = ref([]);
return { avtive, componentList };
</script>
<style>
.content {
height: 100%;
.item-content {
margin: 10px;
.active {
padding: 10px;
border: springgreen 1px solid;
</style>
<template>
<a-layout class="main">
<a-layout>
<a-layout-sider style="margin-right: 8px">
<List />
</a-layout-sider>
<a-layout-content class="content">
<Content />
</a-layout-content>
</a-layout>
</a-layout>
</template>
<script lang='ts'>
import { defineComponent } from "vue";
import List from "@components/List.vue";
import Content from "@components/Content.vue";
export default defineComponent({
name: "App",
components: {
List,
Content,
setup() {},
</script>
<style lang="less">
.main {
height: 100vh;
.content {
background: #ffffff;
.ant-layout-sider {
background: #ffffff !important;
</style>
不管是拖拽排序,数据移动,还是组件生成,拖拽都是一种更简单的交互方式,即托即见即所得,发展都是越来越懒的过程,这也是为什么现在很多的表单设计器井喷。
不要重复造轮子,如果是学习的态度,完全可以自己动手写一个,但是如果是在项目中,如果有现成的轮子,并且很稳定,能满足你的需要,为什么不用呢?