Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(useSorted): new function (#1799)
- Loading branch information
1 parent
e08f758
commit feaa195
Showing
5 changed files
with
273 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<script setup lang="ts"> | ||
import { rand } from '@vueuse/shared' | ||
import { computed, ref } from 'vue' | ||
import { useSorted } from '.' | ||
const objArr = [{ | ||
name: 'John', | ||
age: 40, | ||
}, { | ||
name: 'Jane', | ||
age: 20, | ||
}, { | ||
name: 'Joe', | ||
age: 30, | ||
}, { | ||
name: 'Jenny', | ||
age: 22, | ||
}] | ||
const result2 = useSorted(objArr, (a, b) => a.age - b.age) | ||
const arrText = ref('') | ||
const inputArr = computed(() => arrText.value.split(',')) | ||
const inputOut = useSorted(inputArr) | ||
function randomArr() { | ||
const arr = [] | ||
for (let i = 0; i < rand(10, 20); i++) | ||
arr.push(rand(0, 100)) | ||
arrText.value = arr.join(',') | ||
} | ||
randomArr() | ||
</script> | ||
|
||
<template> | ||
<div> | ||
<div class="flex items-center"> | ||
input: | ||
<input v-model="arrText" type="text"> | ||
</div> | ||
<div> | ||
<button @click="randomArr"> | ||
random | ||
</button> | ||
</div> | ||
output: {{ inputOut }} | ||
</div> | ||
|
||
<div class="mt-10"> | ||
<div>object property sort:</div> | ||
<div>input:</div> | ||
<div>{{ objArr }}</div> | ||
<div class="mt-5"> | ||
output: | ||
</div> | ||
<div>{{ result2 }}</div> | ||
</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,45 @@ | ||
--- | ||
category: Array | ||
--- | ||
|
||
# useSorted | ||
|
||
reactive sort array | ||
|
||
## Usage | ||
|
||
```ts | ||
import { useSorted } from '@vueuse/core' | ||
|
||
// general sort | ||
const source = [10, 3, 5, 7, 2, 1, 8, 6, 9, 4] | ||
const sorted = useSorted(source) | ||
console.log(sorted.value) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | ||
console.log(source) // [10, 3, 5, 7, 2, 1, 8, 6, 9, 4] | ||
|
||
// object sort | ||
const objArr = [{ | ||
name: 'John', | ||
age: 40, | ||
}, { | ||
name: 'Jane', | ||
age: 20, | ||
}, { | ||
name: 'Joe', | ||
age: 30, | ||
}, { | ||
name: 'Jenny', | ||
age: 22, | ||
}] | ||
const objSorted = useSorted(objArr, (a, b) => a.age - b.age) | ||
``` | ||
### dirty mode | ||
|
||
dirty mode will change the source array. | ||
```ts | ||
const source = ref([10, 3, 5, 7, 2, 1, 8, 6, 9, 4]) | ||
const sorted = useSorted(source, (a, b) => a - b, { | ||
dirty: true, | ||
}) | ||
console.log(source)// output: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 | ||
``` |
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,94 @@ | ||
import { unref } from 'vue' | ||
import { useSorted } from '.' | ||
|
||
interface User { | ||
name: string | ||
age: number | ||
} | ||
|
||
const arr = [10, 3, 5, 7, 2, 1, 8, 6, 9, 4] | ||
const arrSorted = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | ||
|
||
const objArr: User[] = [ | ||
{ | ||
name: 'John', | ||
age: 40, | ||
}, | ||
{ | ||
name: 'Jane', | ||
age: 20, | ||
}, | ||
{ | ||
name: 'Joe', | ||
age: 30, | ||
}, | ||
{ | ||
name: 'Jenny', | ||
age: 22, | ||
}, | ||
] | ||
const objectSorted: User[] = [ | ||
{ | ||
name: 'Jane', | ||
age: 20, | ||
}, | ||
{ | ||
name: 'Jenny', | ||
age: 22, | ||
}, | ||
{ | ||
name: 'Joe', | ||
age: 30, | ||
}, | ||
{ | ||
name: 'John', | ||
age: 40, | ||
}, | ||
] | ||
|
||
describe('useSorted', () => { | ||
it('should be defined', () => { | ||
expect(useSorted).toBeDefined() | ||
}) | ||
|
||
it('should pure sort function', () => { | ||
const sorted = useSorted(arr) | ||
expect(unref(sorted)).toMatchObject(arrSorted) | ||
expect(unref(arr)).toMatchInlineSnapshot(` | ||
[ | ||
10, | ||
3, | ||
5, | ||
7, | ||
2, | ||
1, | ||
8, | ||
6, | ||
9, | ||
4, | ||
] | ||
`) | ||
}) | ||
|
||
it('should dirty sort', () => { | ||
const dirtyArr = [...arr] | ||
const sorted = useSorted(dirtyArr, (a, b) => a - b, { dirty: true }) | ||
|
||
expect(unref(sorted)).toMatchObject(arrSorted) | ||
expect(unref(dirtyArr)).toMatchObject(unref(sorted)) | ||
}) | ||
|
||
it('should sort object', () => { | ||
const sorted = useSorted(objArr, (a, b) => a.age - b.age) | ||
|
||
expect(unref(sorted)).toMatchObject(objectSorted) | ||
}) | ||
|
||
it('should sort object by options.compareFn', () => { | ||
const sorted = useSorted(objArr, { | ||
compareFn: (a, b) => a.age - b.age, | ||
}) | ||
|
||
expect(unref(sorted)).toMatchObject(objectSorted) | ||
}) | ||
}) |
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,75 @@ | ||
import type { Ref } from 'vue-demi' | ||
import type { MaybeRef } from '@vueuse/shared' | ||
import { computed, isRef, unref, watchEffect } from 'vue-demi' | ||
|
||
export type UseSortedCompareFn<T = any> = (a: T, b: T) => number | ||
|
||
export type UseSortedFn<T = any> = (arr: T[], compareFn: UseSortedCompareFn<T>) => T[] | ||
|
||
export interface UseSortedOptions<T = any> { | ||
/** | ||
* sort algorithm | ||
*/ | ||
sortFn?: UseSortedFn<T> | ||
/** | ||
* compare function | ||
*/ | ||
compareFn?: UseSortedCompareFn<T> | ||
/** | ||
* change the value of the source array | ||
* @default false | ||
*/ | ||
dirty?: boolean | ||
} | ||
|
||
const defaultSortFn: UseSortedFn = <T>(source: T[], compareFn: UseSortedCompareFn<T>): T[] => source.sort(compareFn) | ||
const defaultCompare: UseSortedCompareFn<number> = (a, b) => a - b | ||
|
||
export function useSorted<T = any>(source: MaybeRef<T[]>, compareFn?: UseSortedCompareFn<T>): Ref<T[]> | ||
export function useSorted<T = any>(source: MaybeRef<T[]>, options?: UseSortedOptions<T>): Ref<T[]> | ||
export function useSorted<T = any>(source: MaybeRef<T[]>, compareFn?: UseSortedCompareFn<T>, options?: Omit<UseSortedOptions<T>, 'compareFn'>): Ref<T[]> | ||
/** | ||
* reactive sort array | ||
* | ||
* @see https://vueuse.org/useSorted | ||
* @param source source array | ||
* @param options | ||
*/ | ||
export function useSorted(...args: any[]) { | ||
const [source] = args | ||
let compareFn: UseSortedCompareFn = defaultCompare | ||
let options: UseSortedOptions = {} | ||
|
||
if (args.length === 2) { | ||
if (typeof args[1] === 'object') { | ||
options = args[1] | ||
compareFn = options.compareFn ?? defaultCompare | ||
} | ||
else { | ||
compareFn = args[1] ?? defaultCompare | ||
} | ||
} | ||
else if (args.length > 2) { | ||
compareFn = args[1] ?? defaultCompare | ||
options = args[2] ?? {} | ||
} | ||
|
||
const { | ||
dirty = false, | ||
sortFn = defaultSortFn, | ||
} = options | ||
|
||
if (!dirty) | ||
return computed(() => sortFn([...unref(source)], compareFn)) | ||
|
||
// dirty | ||
watchEffect(() => { | ||
const result = sortFn(unref(source), compareFn) | ||
if (isRef(source)) | ||
source.value = result | ||
else | ||
source.splice(0, source.length, ...result) | ||
}) | ||
|
||
return source | ||
} |