作用
得到两个数组的差异(响应式),意味着一个数组变了,结果也会响应式变化
例子
普通用法
import { useArrayDifference } from '@vueuse/core'
const list1 = ref([0, 1, 2, 3, 4, 5])
const list2 = ref([4, 5, 6])
const result = useArrayDifference(list1, list2)
// result.value: [0, 1, 2, 3]
list2.value = [0, 1, 2]
// result.value: [3, 4, 5]
自定义对比函数
import { useArrayDifference } from '@vueuse/core'
const list1 = ref([{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }])
const list2 = ref([{ id: 4 }, { id: 5 }, { id: 6 }])
const result = useArrayDifference(list1, list2, (value, othVal) => value.id === othVal.id)
// result.value: [{ id: 1 }, { id: 2 }, { id: 3 }]
自定义key
const list1 = ref([{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }])
const list2 = ref([{ id: 3 }, { id: 4 }, { id: 5 }])
const result = useArrayDifference(list1, list2, 'id')
// result.value: [{ id: 1 }, { id: 2 }]
源码解读
首先使用了函数重载的方式,使得这个函数的参数的多样性,第三个参数可不写,可以是个 字符串表示 key,也可以是一个 对比函数;
核心在于使用了 computed 得到的是结算属性,这样子 list 和 values 变了,result 也会更新,其次是这里使用的是 findIndex 而不是 使用的 !find(y => compareFn(x, y)),避免了 非真值(0, false, null)的干扰
computed(() => toValue(list).filter(x => toValue(values).findIndex(y => compareFn(x, y)) === -1))
import type { ComputedRef } from 'vue-demi'
import { computed } from 'vue-demi'
import type { MaybeRefOrGetter } from '../utils'
import { toValue } from '../toValue'
// 默认对比函数,value 全等于 othVal
function defaultComparator<T>(value: T, othVal: T) {
return value === othVal
}
export function useArrayDifference<T>(list: MaybeRefOrGetter<T[]>, values: MaybeRefOrGetter<T[]>, key?: keyof T): ComputedRef<T[]>
export function useArrayDifference<T>(list: MaybeRefOrGetter<T[]>, values: MaybeRefOrGetter<T[]>, compareFn?: (value: T, othVal: T) => boolean): ComputedRef<T[]>
/**
* Reactive get array difference of two array
* @see https://vueuse.org/useArrayDifference
* @returns - the difference of two array
* @param args
*/
export function useArrayDifference<T>(...args: any[]): ComputedRef<T[]> {
const list: MaybeRefOrGetter<T[]> = args[0]
const values: MaybeRefOrGetter<T[]> = args[1]
let compareFn = args[2] ?? defaultComparator
if (typeof compareFn === 'string') {
const key = compareFn as keyof T
compareFn = (value: T, othVal: T) => value[key] === othVal[key]
}
return computed(() => toValue(list).filter(x => toValue(values).findIndex(y => compareFn(x, y)) === -1))
}
进一步思考
源码,只会得到在数组1中而不在数组2中的数据,但是差异的意思应该是可以筛选出,数组1和数组2不相同的元素才对;
本人优化后的代码如下: 添加了一个options,可选参数,支持合并差异。
import type { ComputedRef } from 'vue-demi'
import { computed } from 'vue-demi'
import type { MaybeRefOrGetter } from '../utils'
import { toValue } from '../toValue'
export interface UseArrayDifferenceOptions {
/**
* Whether to merge differences
* @default false
*/
mergeDiff?: boolean
}
function defaultComparator<T>(value: T, othVal: T) {
return value === othVal
}
export function useArrayDifference<T>(list: MaybeRefOrGetter<T[]>, values: MaybeRefOrGetter<T[]>, key?: keyof T): ComputedRef<T[]>
export function useArrayDifference<T>(list: MaybeRefOrGetter<T[]>, values: MaybeRefOrGetter<T[]>, key?: keyof T, options?: UseArrayDifferenceOptions): ComputedRef<T[]>
export function useArrayDifference<T>(list: MaybeRefOrGetter<T[]>, values: MaybeRefOrGetter<T[]>, compareFn?: (value: T, othVal: T) => boolean): ComputedRef<T[]>
export function useArrayDifference<T>(list: MaybeRefOrGetter<T[]>, values: MaybeRefOrGetter<T[]>, compareFn?: (value: T, othVal: T) => boolean, options?: UseArrayDifferenceOptions): ComputedRef<T[]>
/**
* Reactive get array difference of two array
* @see https://vueuse.org/useArrayDifference
* @returns - the difference of two array
* @param args
*/
export function useArrayDifference<T>(...args: any[]): ComputedRef<T[]> {
const list: MaybeRefOrGetter<T[]> = args[0]
const values: MaybeRefOrGetter<T[]> = args[1]
let compareFn = args[2] ?? defaultComparator
const { mergeDiff = false } = args[3] ?? {}
if (typeof compareFn === 'string') {
const key = compareFn as keyof T
compareFn = (value: T, othVal: T) => value[key] === othVal[key]
}
const diff1 = computed(() => toValue(list).filter(x => toValue(values).findIndex(y => compareFn(x, y)) === -1))
const diff2 = computed(() => toValue(values).filter(x => toValue(list).findIndex(y => compareFn(x, y)) === -1))
const result = computed(() => mergeDiff ? [...toValue(diff1), ...toValue(diff2)] : toValue(diff1))
return result
}