简单使用vue拖拽组件vue3-dnd
vue3-dnd vue3项目拖拽元素以及保存拖拽位置
·
项目中需要使用到拖拽,这里使用vue3-dnd来满足需求
这里项目使用的vue3(使用js而非ts)
插件官网地址:Vue3 DnD
安装
npm install vue3-dnd react-dnd-html5-backend
然后在app.vue里面添加代码
<template>
<DndProvider :backend="HTML5Backend">
<router-view/>
</DndProvider>
</template>
通过DndProvider组件为项目提供拖拽功能
概念
项目item和类型:被拖拽的对象我们称呼为某种类型的项目,类型的作用是让放置目标过滤可以放置的项目
监视器monitor:存放项目的拖动状态,例如项目是否可以放置、项目移动了多少像素等
拖拽的元素drag:可以拖拽的元素,一般用:ref="drag"设置元素可以拖拽(drag是需要调用插件方法设置的ref函数,下面代码进行示例)
放置的元素drop:可以将拖拽的元素放置在此,一般用:ref="drop"设置元素可以放置(drop是需要调用插件方法设置的ref函数,下面代码进行示例)
思路
需求是一个固定大小的元素上有多个可以拖动的元素,拖动后需要保存这些元素的位置
这里先定义一个组件dragBox.vue 每个组件就是一个可以拖动的元素,然后将组件注册全局
// 可拖动的元素类型
export const dragItemType = {
TEXT: 'text',
TABLE: 'table'
}
注意: <div v-if="isDragging" :ref="drag" /> 这个div是必须的。否则只能拖动一次。
<template>
<div v-if="isDragging" :ref="drag" />
<div :ref="drag" class="box" v-else :style="{left:left+'px',top:top+'px',height:height+'px',width:width+'px',fontSize:fontSize+'px'}">
{{ title }}
<slot></slot>
</div>
</template>
<script setup>
import {useDrag} from 'vue3-dnd'
import {defineProps} from 'vue'
import {dragItemType} from "@/util/enum";
import { toRefs } from '@vueuse/core'
const props = defineProps({
id: String,//唯一标识
left: Number,//左边距
top: Number,//上边距
height:Number,//元素高度
width: Number,//元素宽度
fontSize:Number,//字体大小
title: String//文本
})
const [collect, drag] = useDrag(() => ({
type: dragItemType.TEXT,
item: {id: props.id, left: props.left, top: props.top},
collect: monitor => ({
isDragging: monitor.isDragging
})
}))
const { isDragging } = toRefs(collect)
</script>
<style scoped>
.box {
position: absolute;
background-color: white;
border: 1px dashed gray;
cursor: move;
padding:0;
}
</style>
在页面上,我们就可以使用该拖动组件了
<template>
<div>
<div class="container" :ref="drop" style="height:300px;width:300px;">
<drag-box v-for="value in details" :key='value.field' :id="value.field" :top="value.top"
:fontSize="value.fontSize"
:left="value.left" :height="value.height"
:width="value.width" :title="value.title">
</drag-box>
</div>
</div>
</template>
<script setup>
import {ref, reactive, onMounted, watch, inject, computed, toRaw} from 'vue';
import {useDrop} from 'vue3-dnd'
import {dragItemType} from "@/util/enum";
//定义拖拽元素
const details=ref([])
details.value.push({
field:'test1',
title:'测试字段1',
fontSize:'9',
height:'20',
width:'100',
top:'10',
left:'10',
})
details.value.push({
field:'test2',
title:'测试字段2',
fontSize:'9',
height:'30',
width:'150',
top:'50',
left:'50',
})
//移动元素(通过修改子组件的top和left来移动)
const moveBox = (id, top, left) => {
let box = details.value.find(x => x.field === id)
Object.assign(box, {top, left})
}
//定义放置元素,
const [, drop] = useDrop(() => ({
accept: dragItemType.TEXT,
drop(item, monitor) {
const delta = monitor.getDifferenceFromInitialOffset()//获取位移距离
const left = Math.round(item.left + delta.x)//计算移动后的top和left
const top = Math.round(item.top + delta.y)
moveBox(item.id, top, left)
return undefined
}
}))
</script>
<style scoped>
.container {
border: 1px solid grey;
margin: 10px;
position: relative;
}
</style>
补充
更多composition API:https://hcg1023.github.io/vue3-dnd/guide/composition/use-drag.html
更多示例:示例 | Vue3 DnD
本文只提供其中一种简单的应用。
更多推荐
已为社区贡献1条内容
所有评论(0)