index.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. <script setup lang="ts">
  2. import { NAlert, NCard, NSplit, NScrollbar, NButton } from 'naive-ui'
  3. import { ref, watch } from 'vue'
  4. import { VueDraggable } from 'vue-draggable-plus'
  5. import { EmptyPlaceholder } from '@/components'
  6. import type { UseDraggableReturn } from 'vue-draggable-plus'
  7. defineOptions({
  8. name: 'DragDrop',
  9. })
  10. let codeToHtml: any
  11. const APP_NAME = import.meta.env.VITE_APP_NAME
  12. const baseListCodeHighlight = ref()
  13. const gridListCodeHighlight = ref()
  14. const cloneList2CodeHighlight = ref()
  15. const baseList = ref(
  16. Object.keys(Array.from({ length: 4 }).fill(0)).map((item, index) => ({
  17. name: item,
  18. id: index,
  19. })),
  20. )
  21. const gridList = ref(
  22. Object.keys(Array.from({ length: 50 }).fill(0)).map((item, index) => ({
  23. name: Number(item) + 4,
  24. id: index + 4,
  25. })),
  26. )
  27. const taskList = ref(
  28. Object.keys(Array.from({ length: 5 }).fill(0)).map((item) => ({
  29. name: `任务-${item}`,
  30. id: `任务-${item}`,
  31. })),
  32. )
  33. const cloneTaskList = ref<{ name: string; id: string; key: string }[]>([])
  34. const baseDragRef = ref<UseDraggableReturn>()
  35. const gridDragRef = ref<UseDraggableReturn>()
  36. const taskDragRef = ref<UseDraggableReturn>()
  37. const cloneTaskListDragRef = ref<UseDraggableReturn>()
  38. function cloneTask(element: Record<'name' | 'id', string>) {
  39. return {
  40. name: `${element.name}`,
  41. id: `${element.id}`,
  42. key: element.name + new Date().getTime(),
  43. }
  44. }
  45. function removeTask(element: Record<'name' | 'id' | 'key', string>) {
  46. const find = cloneTaskList.value.find((item) => item.key === element.key)
  47. if (find) {
  48. cloneTaskList.value = cloneTaskList.value.filter((item) => item.key !== element.key)
  49. }
  50. }
  51. watch(
  52. [baseList, gridList, cloneTaskList],
  53. async (newVal) => {
  54. const [baseList, gridList, cloneList2] = newVal
  55. if (!codeToHtml) {
  56. // @ts-ignore
  57. const shiki = await import('https://cdn.jsdelivr.net/npm/shiki@3.7.0/+esm')
  58. codeToHtml = shiki.codeToHtml
  59. }
  60. codeToHtml(JSON.stringify(baseList, null, 2), {
  61. lang: 'json',
  62. themes: {
  63. dark: 'dark-plus',
  64. light: 'min-light',
  65. },
  66. })
  67. .then((result: string) => (baseListCodeHighlight.value = result))
  68. .catch(() => (baseListCodeHighlight.value = JSON.stringify(baseList, null, 2)))
  69. codeToHtml(JSON.stringify(gridList, null, 2), {
  70. lang: 'json',
  71. themes: {
  72. dark: 'dark-plus',
  73. light: 'min-light',
  74. },
  75. })
  76. .then((result: string) => (gridListCodeHighlight.value = result))
  77. .catch(() => (gridListCodeHighlight.value = JSON.stringify(gridList, null, 2)))
  78. codeToHtml(JSON.stringify(cloneList2, null, 2), {
  79. lang: 'json',
  80. themes: {
  81. dark: 'dark-plus',
  82. light: 'min-light',
  83. },
  84. })
  85. .then((result: string) => (cloneList2CodeHighlight.value = result))
  86. .catch(() => (cloneList2CodeHighlight.value = JSON.stringify(cloneList2, null, 2)))
  87. },
  88. {
  89. immediate: true,
  90. },
  91. )
  92. </script>
  93. <template>
  94. <div class="flex flex-col gap-y-2 p-4">
  95. <NAlert
  96. type="info"
  97. closable
  98. >
  99. {{ APP_NAME }} 的 Tabs 栏的拖拽模块使用了
  100. vue-draggable-plus,在一些拖拽的场景下,它也许可以帮助到你
  101. </NAlert>
  102. <NCard title="基础使用">
  103. <NSplit
  104. direction="horizontal"
  105. pane1-class="pr-8"
  106. pane2-class="pl-8"
  107. style="height: 280px"
  108. >
  109. <template #1>
  110. <NScrollbar>
  111. <VueDraggable
  112. ref="baseDragRef"
  113. v-model="baseList"
  114. :animation="150"
  115. :scrollSensitivity="100"
  116. ghostClass="ghost"
  117. group="drag1"
  118. class="flex flex-col gap-2 rounded bg-neutral-500/5 p-4 select-none"
  119. >
  120. <div
  121. v-for="item in baseList"
  122. :key="item.id"
  123. class="flex h-14 cursor-move items-center justify-center rounded bg-neutral-500/8 p-3"
  124. >
  125. {{ item.name }}
  126. </div>
  127. </VueDraggable>
  128. </NScrollbar>
  129. </template>
  130. <template #2>
  131. <NScrollbar>
  132. <div v-html="baseListCodeHighlight"></div>
  133. </NScrollbar>
  134. </template>
  135. <template #resize-trigger>
  136. <div class="h-full w-px cursor-col-resize bg-neutral-200 dark:bg-neutral-700"></div>
  137. </template>
  138. </NSplit>
  139. </NCard>
  140. <NCard title="网格布局">
  141. <template #header-extra>
  142. <div>
  143. 你可以把<span class="text-primary">网格布局</span>的元素拖进<span class="text-primary"
  144. >基础使用</span
  145. >中,它们可以相互拖放
  146. </div>
  147. </template>
  148. <NSplit
  149. direction="horizontal"
  150. pane1-class="pr-8"
  151. pane2-class="pl-8"
  152. style="height: 280px"
  153. :default-size="0.7"
  154. >
  155. <template #1>
  156. <NScrollbar>
  157. <VueDraggable
  158. ref="gridDragRef"
  159. v-model="gridList"
  160. :animation="150"
  161. ghostClass="ghost"
  162. group="drag1"
  163. class="m-auto grid grid-cols-8 gap-2 rounded bg-neutral-500/5 p-4 select-none"
  164. >
  165. <div
  166. v-for="item in gridList"
  167. :key="item.id"
  168. class="flex h-14 cursor-move items-center justify-center rounded bg-neutral-500/8 p-3"
  169. >
  170. {{ item.name }}
  171. </div>
  172. </VueDraggable>
  173. </NScrollbar>
  174. </template>
  175. <template #2>
  176. <NScrollbar>
  177. <div v-html="gridListCodeHighlight"></div>
  178. </NScrollbar>
  179. </template>
  180. <template #resize-trigger>
  181. <div class="h-full w-px cursor-col-resize bg-neutral-200 dark:bg-neutral-700"></div>
  182. </template>
  183. </NSplit>
  184. </NCard>
  185. <NCard title="克隆使用">
  186. <NSplit
  187. direction="horizontal"
  188. pane1-class="pr-8"
  189. pane2-class="pl-8"
  190. style="height: 300px"
  191. :default-size="0.7"
  192. >
  193. <template #1>
  194. <div class="flex h-full gap-x-4">
  195. <NScrollbar>
  196. <VueDraggable
  197. ref="taskDragRef"
  198. v-model="taskList"
  199. :animation="150"
  200. :scrollSensitivity="100"
  201. ghostClass="ghost"
  202. :group="{ name: 'clone', pull: 'clone', put: false }"
  203. class="flex flex-col gap-2 rounded bg-neutral-500/5 p-4 select-none"
  204. :clone="cloneTask"
  205. >
  206. <div
  207. v-for="item in taskList"
  208. :key="item.id"
  209. class="flex h-14 cursor-move items-center justify-center rounded bg-neutral-500/8 p-3"
  210. >
  211. {{ item.name }}
  212. </div>
  213. </VueDraggable>
  214. </NScrollbar>
  215. <NScrollbar>
  216. <EmptyPlaceholder
  217. :show="cloneTaskList.length <= 0"
  218. description="把左边的任务拖拽到这里"
  219. />
  220. <VueDraggable
  221. ref="cloneTaskListDragRef"
  222. v-model="cloneTaskList"
  223. :animation="150"
  224. :scrollSensitivity="100"
  225. ghostClass="ghost"
  226. group="clone"
  227. class="flex h-full flex-col gap-2 rounded bg-neutral-500/5 p-4 select-none"
  228. style="min-height: 300px"
  229. >
  230. <div
  231. v-for="item in cloneTaskList"
  232. :key="item.key"
  233. class="flex h-14 cursor-move items-center justify-between rounded bg-neutral-500/8 px-4 py-3"
  234. >
  235. <span>{{ item.name }}</span>
  236. <NButton
  237. quaternary
  238. circle
  239. size="small"
  240. @click="removeTask(item)"
  241. >
  242. <template #icon>
  243. <span class="iconify ph--x"></span>
  244. </template>
  245. </NButton>
  246. </div>
  247. </VueDraggable>
  248. </NScrollbar>
  249. </div>
  250. </template>
  251. <template #2>
  252. <NScrollbar>
  253. <div v-html="cloneList2CodeHighlight"></div>
  254. </NScrollbar>
  255. </template>
  256. <template #resize-trigger>
  257. <div class="h-full w-px cursor-col-resize bg-neutral-200 dark:bg-neutral-700"></div>
  258. </template>
  259. </NSplit>
  260. </NCard>
  261. </div>
  262. </template>