useSwap
一个在 Vue 中使用的组合式函数(hook),用于封装 SwapDrag,以响应式的方式在组件中启用拖拽排序。
- 通过
ref传入容器元素,onMounted时自动初始化,onUnmounted时自动销毁 - 提供
isDragging响应式状态,方便在拖拽期间控制 UI - 暴露
init/destroy/reinitialize方法,便于手动管理生命周期 - 支持
autoInit选项控制是否自动初始化
示例
1
2
3
4
5
6
7
8
9
10
示例代码
vue
<script setup lang="ts">
import { nextTick, reactive, ref } from 'vue'
import { useSwap } from './code'
import { random } from '../../../utils/random/code'
import { sleep } from '../../../utils/sleep/code'
defineOptions({ name: 'Example6' })
const list = reactive([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
const el = ref<HTMLElement>()
useSwap(el, {
async onSort({ draggedIndex, targetIndex }, swap) {
console.log('onSort', draggedIndex, targetIndex)
await sleep(random(50, 300)) // 模拟请求
const [tmp] = list.splice(draggedIndex, 1)
list.splice(targetIndex, 0, tmp!)
await nextTick()
await swap()
},
})
</script>
<template>
<div ref="el" class="container">
<div v-for="item in list" :key="item" :data-id="item" class="item">{{ item }}</div>
</div>
</template>
<style lang="scss" scoped>
.container {
display: flex;
flex-direction: column;
gap: 16px;
}
:deep(.item) {
position: relative;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
background-color: var(--vp-c-bg-soft);
&.swap-chosen {
background-color: var(--vp-c-brand-3);
}
&.swap-before::after,
&.swap-after::after {
content: '';
position: absolute;
left: 0;
width: 100%;
height: 3px;
background-color: plum;
pointer-events: none;
}
&.swap-before::after {
bottom: calc(100% + 8px);
transform: translateY(50%);
}
&.swap-after::after {
top: calc(100% + 8px);
transform: translateY(-50%);
}
}
</style>code
ts
import { onMounted, onUnmounted, ref, Ref } from 'vue'
import { SwapDrag } from '../../../utils/browser/swap-drag/code'
import type { SwapDragOptions } from '../../../utils/browser/swap-drag/code'
export interface UseSwapOptions extends SwapDragOptions {
autoInit?: boolean
}
export function useSwap(
el: Ref<HTMLElement | undefined>,
options: UseSwapOptions = {},
) {
const { autoInit = true, ...restOptions } = options
const instance = ref<SwapDrag>()
const isDragging = ref(false)
const init = () => {
if (!el.value) return
instance.value = new SwapDrag(el.value, {
...restOptions,
onStart(e) {
isDragging.value = true
restOptions.onStart?.(e)
},
onEnd() {
isDragging.value = false
restOptions.onEnd?.()
},
})
}
const destroy = () => instance.value?.destroy()
const reinitialize = () => {
destroy()
init()
}
if (autoInit) onMounted(init)
onUnmounted(destroy)
return { instance, isDragging, init, destroy, reinitialize }
}