UNPKG

vue3-dnd

Version:

Drag and Drop for Vue Composition API

246 lines (211 loc) 7.41 kB
# Vue3 Dn<img src="http://image.haochenguang.cn/pictures/vue3-dnd.svg" width="28"> ## 文档 [vue3-dnd.com](https://www.vue3-dnd.com) React Dnd 的 Composition-api 实现。 **支持Vue2和Vue3** 如果你觉得这个项目对你有帮助,希望你能贡献一个 [star⭐](https://github.com/hcg1023/vue3-dnd) [![npm version](https://img.shields.io/npm/v/vue3-dnd.svg?style=flat-square)](https://www.npmjs.com/package/vue3-dnd) [![CI](https://github.com/hcg1023/vue3-dnd/actions/workflows/ci.yml/badge.svg)](https://github.com/hcg1023/vue3-dnd/actions/workflows/ci.yml) [![install size](https://img.shields.io/badge/dynamic/json?url=https://packagephobia.com/v2/api.json?p=vue3-dnd&query=$.install.pretty&label=install%20size&style=flat-square)](https://packagephobia.now.sh/result?p=vue3-dnd) [![npm bundle size](https://img.shields.io/bundlephobia/minzip/vue3-dnd?style=flat-square)](https://bundlephobia.com/package/vue3-dnd@latest) [![GitHub open issues](https://img.shields.io/github/issues/hcg1023/vue3-dnd.svg)](https://github.com/hcg1023/vue3-dnd/issues?q=is%3Aopen+is%3Aissue) [![GitHub Stars](https://img.shields.io/github/stars/hcg1023/vue3-dnd.svg)](https://github.com/hcg1023/vue3-dnd/stargazers) [![GitHub Forks](https://img.shields.io/github/forks/hcg1023/vue3-dnd)](https://github.com/hcg1023/vue3-dnd/network/members) [![GitHub PR](https://img.shields.io/github/issues-pr/hcg1023/vue3-dnd)](https://github.com/hcg1023/vue3-dnd/pulls) [![GitHub contributors](https://img.shields.io/github/contributors/hcg1023/vue3-dnd?color=2b9348)](https://github.com/hcg1023/vue3-dnd/graphs/contributors) [![npm download](https://img.shields.io/npm/dt/vue3-dnd.svg?maxAge=30)](https://www.npmjs.com/package/vue3-dnd) [![npm download per month](https://img.shields.io/npm/dm/vue3-dnd.svg?style=flat-square)](https://www.npmjs.com/package/vue3-dnd) [![Featured on Openbase](https://badges.openbase.com/js/featured/vue3-dnd.svg?token=DweDwkc7YaNcSSwPw5ToxjJyG/CPuAX7J7sZFXKUg9c=)](https://openbase.com/js/vue3-dnd?utm_source=embedded&amp;utm_medium=badge&amp;utm_campaign=rate-badge) [![MIT License](https://img.shields.io/github/license/hcg1023/vue3-dnd.svg)](https://github.com/hcg1023/vue3-dnd/blob/main/LICENSE) **[中文](README_ZH.md)** | **[English](README.md)** ## 使用 ``` npm install vue3-dnd yarn add vue3-dnd pnpm install vue3-dnd ``` ```vue // App.vue <script> import { DndProvider } from 'vue3-dnd' import { HTML5Backend } from 'react-dnd-html5-backend' import Home from './Home.vue' </script> <template> <DndProvider :backend="HTML5Backend"> <Home></Home> </DndProvider> </template> // Home.vue <script> import { useDrag, useDrop, useDragLayer } from 'vue3-dnd' // 开始你的杰作 </script> ``` ## 注意 1. **由于 composition-api 的限制,请不要尝试从 useDrag 和 useDrop 等钩子中解构 collect 参数,这样会失去响应性,例如:** ```ts import { useDrag } from 'vue3-dnd' import { toRefs } from '@vueuse/core' const [collect, drag] = useDrag(() => ({ type: props.type, item: {name: props.name}, collect: monitor => ({ opacity: monitor.isDragging() ? 0.4 : 1, }), })) // good const opacity = computed(() => unref(collect).opacity) // 如果希望解构,可以使用@vueuse/core提供的toRefs const { opacity } = toRefs(collect) // bad const {opacity} = collect.value ``` 2. **`drag drop dragPreview`等ref是一个函数,在template中请使用`v-bind:ref="drag"`,您也可以在一个新的函数中调用它们** ```vue <template> <div :ref="drag">box</div> <div :ref="setDrop">drop div <section> drop section </section> </div> </template> <script lang="ts" setup> import { useDrag, useDrop } from 'vue3-dnd' const [, drag] = useDrag(() => ({ type: 'Box', })) const [, drop] = useDrop(() => ({ type: 'Box' })) // 你还可以使用新函数为其设置值 const setDrop = (el: HTMLDivElement | null) => { drop(el) // or drop(el?.querySelector('section') || null) } </script> ``` ## 示例 ### App.vue ```vue <script setup lang="ts"> import { DndProvider } from 'vue3-dnd' import { HTML5Backend } from 'react-dnd-html5-backend' import Example from './Example.vue' </script> <template> <DndProvider :backend="HTML5Backend"> <Example></Example> </DndProvider> </template> ``` #### Example.vue ```vue <script lang="ts" setup> import { useDrag, useDrop } from 'vue3-dnd' import { computed, unref } from 'vue' const [dropCollect, drop] = useDrop(() => ({ accept: 'Box', drop: () => ({ name: 'Dustbin' }), collect: monitor => ({ isOver: monitor.isOver(), canDrop: monitor.canDrop(), }), })) const canDrop = computed(() => unref(dropCollect).canDrop) const isOver = computed(() => unref(dropCollect).isOver) const isActive = computed(() => unref(canDrop) && unref(isOver)) const backgroundColor = computed(() => unref(isActive) ? 'darkgreen' : unref(canDrop) ? 'darkkhaki' : '#222' ) const [collect, drag] = useDrag(() => ({ type: 'Box', item: () => ({ name: 'Box', }), end: (item, monitor) => { const dropResult = monitor.getDropResult<{ name: string }>() if (item && dropResult) { alert(`You dropped ${item.name} into ${dropResult.name}!`) } }, collect: monitor => ({ isDragging: monitor.isDragging(), handlerId: monitor.getHandlerId(), }), })) const isDragging = computed(() => collect.value.isDragging) const opacity = computed(() => (unref(isDragging) ? 0.4 : 1)) </script> <template> <div> <div :style="{ overflow: 'hidden', clear: 'both' }"> <div :ref="drop" role="Dustbin" class="drop-container" :style="{ backgroundColor }" > {{ isActive ? 'Release to drop' : 'Drag a box here' }} </div> </div> <div :style="{ overflow: 'hidden', clear: 'both' }"> <div :ref="drag" class="box" role="Box" :style="{ opacity }">Box</div> </div> </div> </template> <style lang="less" scoped> .drop-container { height: 12rem; width: 12rem; margin-right: 1.5rem; margin-bottom: 1.5rem; color: white; padding: 1rem; text-align: center; font-size: 1rem; line-height: normal; float: left; } .box { border: 1px solid gray; background-color: white; padding: 0.5rem 1rem; margin-right: 1.5rem; margin-bottom: 1.5rem; cursor: move; float: left; &.dragging { opacity: 0.4; } } </style> ``` ## Q/A ### Q: 在拖动期间或拖动完成之后数据没有更改 A: 检查你的spec 或者 item是否是函数,如果你的item是静态对象,则在拖放过程中你不会得到响应式的数据更改 ```ts // 以下情况可能导致没有反应 const [collect, connectDrag] = useDrag({ type: 'box', item: { id: props.id }, }) // 正确的写法 const [collect, connectDrag] = useDrag({ type: 'box', item: () => ({ id: props.id }), }) const [collect, connectDrag] = useDrag(() => ({ type: 'box', item: { id: props.id }, })) ``` ## 贡献者 <a href="https://github.com/hcg1023/vue3-dnd/graphs/contributors"> <img src="https://contrib.rocks/image?repo=hcg1023/vue3-dnd" /> </a> Made with [contrib.rocks](https://contrib.rocks). ## 感谢 [React-Dnd](https://github.com/react-dnd/react-dnd)