-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(useSortable): new function (#2763)
Co-authored-by: Jelf <353742991@qq.com> Co-authored-by: Jelf <okxiaoliang4@gmail.com> Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
- Loading branch information
1 parent
12c2038
commit 6bc6089
Showing
9 changed files
with
256 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { type PropType, defineComponent, h, reactive, ref } from 'vue-demi' | ||
import { useVModel } from '@vueuse/core' | ||
import { type UseSortableOptions, useSortable } from '.' | ||
|
||
export const UseSortable = /* #__PURE__ */ defineComponent({ | ||
name: 'UseSortable', | ||
model: { // Compatible with vue2 | ||
prop: 'modelValue', | ||
event: 'update:modelValue', | ||
}, | ||
props: { | ||
modelValue: { | ||
type: Array as PropType<any[]>, | ||
required: true, | ||
}, | ||
tag: { | ||
type: String, | ||
default: 'div', | ||
}, | ||
options: { | ||
type: Object as PropType<UseSortableOptions>, | ||
required: true, | ||
}, | ||
}, | ||
|
||
setup(props, { slots }) { | ||
const list = useVModel(props, 'modelValue') | ||
const target = ref() | ||
const data = reactive(useSortable(target, list, props.options)) | ||
return () => { | ||
if (slots.default) | ||
return h(props.tag, { ref: target }, slots.default(data)) | ||
} | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<script setup lang="ts"> | ||
import { useSortable } from '@vueuse/integrations/useSortable' | ||
import { ref } from 'vue' | ||
const el = ref<HTMLElement | null>(null) | ||
const list = ref([{ id: 1, name: 'a' }, { id: 2, name: 'b' }, { id: 3, name: 'c' }]) | ||
useSortable(el, list, { | ||
animation: 150, | ||
}) | ||
</script> | ||
|
||
<template> | ||
<div ref="el" class="flex flex-col gap-2 p-4 w-300px h-200px m-auto bg-gray-500/5 rounded"> | ||
<div v-for="item in list" :key="item.id" class="h20 bg-gray-500/5 rounded p-3"> | ||
{{ item.name }} | ||
</div> | ||
</div> | ||
<div class="text-center"> | ||
{{ JSON.stringify(list) }} | ||
</div> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
--- | ||
category: '@Integrations' | ||
--- | ||
|
||
# useSortable | ||
|
||
Wrapper for [`sortable`](https://github.com/SortableJS/Sortable). | ||
|
||
For more information on what options can be passed, see [`Sortable.options`](https://github.com/SortableJS/Sortable#options) in the `Sortable` documentation. | ||
|
||
## Install | ||
|
||
```bash | ||
npm i sortablejs | ||
``` | ||
|
||
## Usage | ||
|
||
### Use template ref | ||
|
||
```vue | ||
<script setup lang="ts"> | ||
import { useSortable } from '@vueuse/integrations/useSortable' | ||
import { ref } from 'vue' | ||
const el = ref<HTMLElement | null>(null) | ||
const list = ref([{ id: 1, name: 'a' }, { id: 2, name: 'b' }, { id: 3, name: 'c' }]) | ||
useSortable(el, list) | ||
</script> | ||
<template> | ||
<div ref="el"> | ||
<div v-for="item in list" :key="item.id"> | ||
{{ item.name }} | ||
</div> | ||
</div> | ||
</template> | ||
``` | ||
|
||
### Use specifies the selector to operate on | ||
|
||
```vue | ||
<script setup lang="ts"> | ||
import { useSortable } from '@vueuse/integrations/useSortable' | ||
import { ref } from 'vue' | ||
const el = ref<HTMLElement | null>(null) | ||
const list = ref([{ id: 1, name: 'a' }, { id: 2, name: 'b' }, { id: 3, name: 'c' }]) | ||
useSortable(el, list, { | ||
handle: '.handle' | ||
}) | ||
</script> | ||
<template> | ||
<div ref="el"> | ||
<div v-for="item in list" :key="item.id"> | ||
<span>{{ item.name }}</span> | ||
<span class="handle">*</span> | ||
</div> | ||
</div> | ||
</template> | ||
``` | ||
|
||
### Use a selector to get the root element | ||
|
||
```vue | ||
<script setup lang="ts"> | ||
import { useSortable } from '@vueuse/integrations/useSortable' | ||
import { ref } from 'vue' | ||
const list = ref([{ id: 1, name: 'a' }, { id: 2, name: 'b' }, { id: 3, name: 'c' }]) | ||
useSortable('#dv', list) | ||
</script> | ||
<template> | ||
<div id="dv"> | ||
<div v-for="item in list" :key="item.id"> | ||
<span>{{ item.name }}</span> | ||
</div> | ||
</div> | ||
</template> | ||
``` | ||
|
||
### Tips | ||
|
||
If you want to handle the onUpdate yourself, you can pass in onUpdate parameters, and we also exposed a function to move the item position. | ||
|
||
```ts | ||
import { moveArrayElement } from '@vueuse/integrations/useSortable' | ||
|
||
useSortable(el, list, { | ||
onUpdate: (e) => { | ||
// do something | ||
moveArrayElement(list.value, e.oldIndex, e.newIndex) | ||
// do something | ||
} | ||
}) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { defaultDocument, resolveUnref, tryOnMounted, tryOnScopeDispose, unrefElement } from '@vueuse/core' | ||
import type { ConfigurableDocument, MaybeComputedRef } from '@vueuse/core' | ||
import Sortable, { type Options } from 'sortablejs' | ||
|
||
export interface UseSortableReturn { | ||
/** | ||
* start sortable instance | ||
*/ | ||
start: () => void | ||
/** | ||
* destroy sortable instance | ||
*/ | ||
stop: () => void | ||
} | ||
|
||
export type UseSortableOptions = Options & ConfigurableDocument | ||
|
||
export function useSortable<T>(selector: string, list: MaybeComputedRef<T[]>, | ||
options?: UseSortableOptions): UseSortableReturn | ||
export function useSortable<T>(el: MaybeComputedRef<HTMLElement | null | undefined>, list: MaybeComputedRef<T[]>, | ||
options?: UseSortableOptions): UseSortableReturn | ||
/** | ||
* Wrapper for sortablejs. | ||
* @param el | ||
* @param list | ||
* @param options | ||
*/ | ||
export function useSortable<T>( | ||
el: MaybeComputedRef<HTMLElement | null | undefined> | string, | ||
list: MaybeComputedRef<T[]>, | ||
options: UseSortableOptions = {}, | ||
): UseSortableReturn { | ||
let sortable: Sortable | ||
|
||
const { document = defaultDocument, ...resetOptions } = options | ||
|
||
const defaultOptions: Options = { | ||
onUpdate: (e) => { | ||
moveArrayElement(list, e.oldIndex!, e.newIndex!) | ||
}, | ||
} | ||
|
||
const start = () => { | ||
const target = (typeof el === 'string' ? document?.querySelector(el) : unrefElement(el)) | ||
if (!target) | ||
return | ||
sortable = new Sortable(target as HTMLElement, { ...defaultOptions, ...resetOptions }) | ||
} | ||
|
||
const stop = () => sortable?.destroy() | ||
|
||
tryOnMounted(start) | ||
|
||
tryOnScopeDispose(stop) | ||
|
||
return { stop, start } | ||
} | ||
|
||
export function moveArrayElement<T>( | ||
list: MaybeComputedRef<T[]>, | ||
from: number, | ||
to: number, | ||
): void { | ||
const array = resolveUnref(list) | ||
if (to >= 0 && to < array.length) | ||
array.splice(to, 0, array.splice(from, 1)[0]) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.