mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
refactor: 移除 VueDraggable 插件
This commit is contained in:
parent
45a7ed9b46
commit
ce58277e12
38
package-lock.json
generated
38
package-lock.json
generated
@ -36,6 +36,7 @@
|
|||||||
"prosemirror-state": "^1.4.1",
|
"prosemirror-state": "^1.4.1",
|
||||||
"prosemirror-view": "^1.27.2",
|
"prosemirror-view": "^1.27.2",
|
||||||
"register-service-worker": "^1.7.2",
|
"register-service-worker": "^1.7.2",
|
||||||
|
"sortablejs": "^1.15.0",
|
||||||
"svg-arc-to-cubic-bezier": "^3.2.0",
|
"svg-arc-to-cubic-bezier": "^3.2.0",
|
||||||
"svg-pathdata": "^6.0.0",
|
"svg-pathdata": "^6.0.0",
|
||||||
"tinycolor2": "^1.6.0",
|
"tinycolor2": "^1.6.0",
|
||||||
@ -50,6 +51,7 @@
|
|||||||
"@types/file-saver": "^2.0.1",
|
"@types/file-saver": "^2.0.1",
|
||||||
"@types/lodash": "^4.14.181",
|
"@types/lodash": "^4.14.181",
|
||||||
"@types/resize-observer-browser": "^0.1.4",
|
"@types/resize-observer-browser": "^0.1.4",
|
||||||
|
"@types/sortablejs": "^1.15.0",
|
||||||
"@types/svg-arc-to-cubic-bezier": "^3.2.0",
|
"@types/svg-arc-to-cubic-bezier": "^3.2.0",
|
||||||
"@types/tinycolor2": "^1.4.3",
|
"@types/tinycolor2": "^1.4.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
@ -2936,6 +2938,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/sortablejs": {
|
||||||
|
"version": "1.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.0.tgz",
|
||||||
|
"integrity": "sha512-qrhtM7M41EhH4tZQTNw2/RJkxllBx3reiJpTbgWCM2Dx0U1sZ6LwKp9lfNln9uqE26ZMKUaPEYaD4rzvOWYtZw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/svg-arc-to-cubic-bezier": {
|
"node_modules/@types/svg-arc-to-cubic-bezier": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz",
|
||||||
@ -13170,9 +13178,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sortablejs": {
|
"node_modules/sortablejs": {
|
||||||
"version": "1.14.0",
|
"version": "1.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
|
||||||
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
|
"integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w=="
|
||||||
},
|
},
|
||||||
"node_modules/source-list-map": {
|
"node_modules/source-list-map": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
@ -14890,6 +14898,11 @@
|
|||||||
"vue": "^3.0.1"
|
"vue": "^3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vuedraggable/node_modules/sortablejs": {
|
||||||
|
"version": "1.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
||||||
|
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
|
||||||
|
},
|
||||||
"node_modules/w3c-keyname": {
|
"node_modules/w3c-keyname": {
|
||||||
"version": "2.2.6",
|
"version": "2.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz",
|
||||||
@ -18125,6 +18138,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/sortablejs": {
|
||||||
|
"version": "1.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.0.tgz",
|
||||||
|
"integrity": "sha512-qrhtM7M41EhH4tZQTNw2/RJkxllBx3reiJpTbgWCM2Dx0U1sZ6LwKp9lfNln9uqE26ZMKUaPEYaD4rzvOWYtZw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/svg-arc-to-cubic-bezier": {
|
"@types/svg-arc-to-cubic-bezier": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz",
|
||||||
@ -25769,9 +25788,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sortablejs": {
|
"sortablejs": {
|
||||||
"version": "1.14.0",
|
"version": "1.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
|
||||||
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
|
"integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w=="
|
||||||
},
|
},
|
||||||
"source-list-map": {
|
"source-list-map": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
@ -27058,6 +27077,13 @@
|
|||||||
"integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
|
"integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"sortablejs": "1.14.0"
|
"sortablejs": "1.14.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"sortablejs": {
|
||||||
|
"version": "1.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
||||||
|
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"w3c-keyname": {
|
"w3c-keyname": {
|
||||||
|
@ -37,11 +37,11 @@
|
|||||||
"prosemirror-state": "^1.4.1",
|
"prosemirror-state": "^1.4.1",
|
||||||
"prosemirror-view": "^1.27.2",
|
"prosemirror-view": "^1.27.2",
|
||||||
"register-service-worker": "^1.7.2",
|
"register-service-worker": "^1.7.2",
|
||||||
|
"sortablejs": "^1.15.0",
|
||||||
"svg-arc-to-cubic-bezier": "^3.2.0",
|
"svg-arc-to-cubic-bezier": "^3.2.0",
|
||||||
"svg-pathdata": "^6.0.0",
|
"svg-pathdata": "^6.0.0",
|
||||||
"tinycolor2": "^1.6.0",
|
"tinycolor2": "^1.6.0",
|
||||||
"vue": "^3.2.47",
|
"vue": "^3.2.47"
|
||||||
"vuedraggable": "^4.1.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^17.4.4",
|
"@commitlint/cli": "^17.4.4",
|
||||||
@ -51,6 +51,7 @@
|
|||||||
"@types/file-saver": "^2.0.1",
|
"@types/file-saver": "^2.0.1",
|
||||||
"@types/lodash": "^4.14.181",
|
"@types/lodash": "^4.14.181",
|
||||||
"@types/resize-observer-browser": "^0.1.4",
|
"@types/resize-observer-browser": "^0.1.4",
|
||||||
|
"@types/sortablejs": "^1.15.0",
|
||||||
"@types/svg-arc-to-cubic-bezier": "^3.2.0",
|
"@types/svg-arc-to-cubic-bezier": "^3.2.0",
|
||||||
"@types/tinycolor2": "^1.4.3",
|
"@types/tinycolor2": "^1.4.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
|
86
src/components/Sortable.vue
Normal file
86
src/components/Sortable.vue
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="containerRef" :class="$props.class">
|
||||||
|
<slot
|
||||||
|
v-for="(item, index) in list"
|
||||||
|
:key="item[props.itemKey]"
|
||||||
|
:element="item"
|
||||||
|
:index="index"
|
||||||
|
name="item"
|
||||||
|
></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, PropType, watch, onUnmounted } from 'vue'
|
||||||
|
import Sortable, { SortableOptions, SortableEvent } from 'sortablejs'
|
||||||
|
import type { AutoScrollOptions } from 'sortablejs/plugins'
|
||||||
|
|
||||||
|
type SortableOptionsProp = SortableOptions | AutoScrollOptions
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
options: {
|
||||||
|
type: Object as PropType<SortableOptionsProp>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
type: Array as PropType<any[]>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
itemKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(event: 'start', payload: SortableEvent): void
|
||||||
|
(event: 'end', payload: SortableEvent): void
|
||||||
|
(event: 'add', payload: SortableEvent): void
|
||||||
|
(event: 'remove', payload: SortableEvent): void
|
||||||
|
(event: 'update', payload: SortableEvent): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const isDragging = ref(false)
|
||||||
|
const containerRef = ref<HTMLElement | null>(null)
|
||||||
|
const sortable = ref<Sortable | null>(null)
|
||||||
|
|
||||||
|
watch(containerRef, container => {
|
||||||
|
if (container) {
|
||||||
|
sortable.value = new Sortable(container, {
|
||||||
|
...props.options,
|
||||||
|
onStart: event => {
|
||||||
|
isDragging.value = true
|
||||||
|
emit('start', event)
|
||||||
|
},
|
||||||
|
onEnd: event => {
|
||||||
|
setTimeout(() => {
|
||||||
|
isDragging.value = false
|
||||||
|
emit('end', event)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onAdd: event => emit('add', event),
|
||||||
|
onRemove: event => emit('remove', event),
|
||||||
|
onUpdate: event => emit('update', event),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props.options, options => {
|
||||||
|
if (options && sortable.value) {
|
||||||
|
for (const key in options) {
|
||||||
|
const name = key as keyof SortableOptionsProp
|
||||||
|
const value = options[key as keyof SortableOptionsProp]
|
||||||
|
sortable.value.option(name, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (sortable.value) {
|
||||||
|
sortable.value.destroy()
|
||||||
|
containerRef.value = null
|
||||||
|
sortable.value = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
@ -15,13 +15,14 @@
|
|||||||
</Popover>
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Draggable
|
<Sortable
|
||||||
class="thumbnail-list"
|
class="thumbnail-list"
|
||||||
:modelValue="slides"
|
:list="slides"
|
||||||
:animation="300"
|
:options="{
|
||||||
:scroll="true"
|
animation: 200,
|
||||||
:scrollSensitivity="50"
|
scroll: true,
|
||||||
:setData="null"
|
scrollSensitivity: 50,
|
||||||
|
}"
|
||||||
@end="handleDragEnd"
|
@end="handleDragEnd"
|
||||||
itemKey="id"
|
itemKey="id"
|
||||||
>
|
>
|
||||||
@ -39,7 +40,7 @@
|
|||||||
<ThumbnailSlide class="thumbnail" :slide="element" :size="120" :visible="index < slidesLoadLimit" />
|
<ThumbnailSlide class="thumbnail" :slide="element" :size="120" :visible="index < slidesLoadLimit" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Draggable>
|
</Sortable>
|
||||||
|
|
||||||
<div class="page-number">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div>
|
<div class="page-number">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div>
|
||||||
</div>
|
</div>
|
||||||
@ -55,7 +56,8 @@ import useSlideHandler from '@/hooks/useSlideHandler'
|
|||||||
import useScreening from '@/hooks/useScreening'
|
import useScreening from '@/hooks/useScreening'
|
||||||
import useLoadSlides from '@/hooks/useLoadSlides'
|
import useLoadSlides from '@/hooks/useLoadSlides'
|
||||||
|
|
||||||
import Draggable from 'vuedraggable'
|
import { SortableEvent } from 'sortablejs'
|
||||||
|
import Sortable from '@/components/Sortable.vue'
|
||||||
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
||||||
import LayoutPool from './LayoutPool.vue'
|
import LayoutPool from './LayoutPool.vue'
|
||||||
import { Popover } from 'ant-design-vue'
|
import { Popover } from 'ant-design-vue'
|
||||||
@ -153,8 +155,9 @@ const setThumbnailsFocus = (focus: boolean) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 拖拽调整顺序后进行数据的同步
|
// 拖拽调整顺序后进行数据的同步
|
||||||
const handleDragEnd = (eventData: { newIndex: number; oldIndex: number }) => {
|
const handleDragEnd = (eventData: SortableEvent) => {
|
||||||
const { newIndex, oldIndex } = eventData
|
const { newIndex, oldIndex } = eventData
|
||||||
|
if (newIndex === undefined || oldIndex === undefined || newIndex === oldIndex) return
|
||||||
sortSlides(newIndex, oldIndex)
|
sortSlides(newIndex, oldIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,15 +52,17 @@
|
|||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Draggable
|
<Sortable
|
||||||
class="animation-sequence"
|
class="animation-sequence"
|
||||||
:modelValue="animationSequence"
|
:list="animationSequence"
|
||||||
:animation="300"
|
:options="{
|
||||||
:scroll="true"
|
animation: 200,
|
||||||
:scrollSensitivity="50"
|
scroll: true,
|
||||||
handle=".sequence-content"
|
scrollSensitivity: 50,
|
||||||
@end="handleDragEnd"
|
handle: '.sequence-content',
|
||||||
|
}"
|
||||||
itemKey="id"
|
itemKey="id"
|
||||||
|
@end="handleDragEnd"
|
||||||
>
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
<div class="sequence-item" :class="[element.type, { 'active': handleElement?.id === element.elId }]">
|
<div class="sequence-item" :class="[element.type, { 'active': handleElement?.id === element.elId }]">
|
||||||
@ -109,7 +111,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Draggable>
|
</Sortable>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -130,7 +132,8 @@ import {
|
|||||||
import { ELEMENT_TYPE_ZH } from '@/configs/element'
|
import { ELEMENT_TYPE_ZH } from '@/configs/element'
|
||||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||||
|
|
||||||
import Draggable from 'vuedraggable'
|
import { SortableEvent } from 'sortablejs'
|
||||||
|
import Sortable from '@/components/Sortable.vue'
|
||||||
import {
|
import {
|
||||||
InputNumber,
|
InputNumber,
|
||||||
Divider,
|
Divider,
|
||||||
@ -224,9 +227,9 @@ const deleteAnimation = (id: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 拖拽修改动画顺序后同步数据
|
// 拖拽修改动画顺序后同步数据
|
||||||
const handleDragEnd = (eventData: { newIndex: number; oldIndex: number }) => {
|
const handleDragEnd = (eventData: SortableEvent) => {
|
||||||
const { newIndex, oldIndex } = eventData
|
const { newIndex, oldIndex } = eventData
|
||||||
if (oldIndex === newIndex) return
|
if (newIndex === undefined || oldIndex === undefined || newIndex === oldIndex) return
|
||||||
|
|
||||||
const animations: PPTAnimation[] = JSON.parse(JSON.stringify(currentSlideAnimations.value))
|
const animations: PPTAnimation[] = JSON.parse(JSON.stringify(currentSlideAnimations.value))
|
||||||
const animation = animations[oldIndex]
|
const animation = animations[oldIndex]
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mobile-thumbnails">
|
<div class="mobile-thumbnails">
|
||||||
<Draggable
|
<Sortable
|
||||||
class="thumbnail-list"
|
class="thumbnail-list"
|
||||||
:modelValue="slides"
|
:list="slides"
|
||||||
:animation="300"
|
:options="{
|
||||||
:scroll="true"
|
animation: 200,
|
||||||
:scrollSensitivity="50"
|
scroll: true,
|
||||||
:setData="null"
|
scrollSensitivity: 50,
|
||||||
|
delayOnTouchOnly: true,
|
||||||
|
delay: 800,
|
||||||
|
}"
|
||||||
itemKey="id"
|
itemKey="id"
|
||||||
:delayOnTouchOnly="true"
|
|
||||||
:delay="800"
|
|
||||||
@end="handleDragEnd"
|
@end="handleDragEnd"
|
||||||
>
|
>
|
||||||
<template #item="{ element, index }">
|
<template #item="{ element, index }">
|
||||||
@ -22,7 +23,7 @@
|
|||||||
<ThumbnailSlide class="thumbnail" :slide="element" :size="120" :visible="index < slidesLoadLimit" />
|
<ThumbnailSlide class="thumbnail" :slide="element" :size="120" :visible="index < slidesLoadLimit" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Draggable>
|
</Sortable>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -32,7 +33,8 @@ import { useSlidesStore } from '@/store'
|
|||||||
import useLoadSlides from '@/hooks/useLoadSlides'
|
import useLoadSlides from '@/hooks/useLoadSlides'
|
||||||
import useSlideHandler from '@/hooks/useSlideHandler'
|
import useSlideHandler from '@/hooks/useSlideHandler'
|
||||||
|
|
||||||
import Draggable from 'vuedraggable'
|
import { SortableEvent } from 'sortablejs'
|
||||||
|
import Sortable from '@/components/Sortable.vue'
|
||||||
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
||||||
|
|
||||||
const slidesStore = useSlidesStore()
|
const slidesStore = useSlidesStore()
|
||||||
@ -46,8 +48,9 @@ const changeSlideIndex = (index: number) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 拖拽调整顺序后进行数据的同步
|
// 拖拽调整顺序后进行数据的同步
|
||||||
const handleDragEnd = (eventData: { newIndex: number; oldIndex: number }) => {
|
const handleDragEnd = (eventData: SortableEvent) => {
|
||||||
const { newIndex, oldIndex } = eventData
|
const { newIndex, oldIndex } = eventData
|
||||||
|
if (newIndex === undefined || oldIndex === undefined || newIndex === oldIndex) return
|
||||||
sortSlides(newIndex, oldIndex)
|
sortSlides(newIndex, oldIndex)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user