vuecssuiant-designantdreactantantd-vueenterprisefrontendui-designvue-antdvue-antd-uivue3vuecomponent
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
62 lines
1.7 KiB
62 lines
1.7 KiB
import type { VNodeProps, Ref, ShallowRef } from 'vue'; |
|
import { watch, ref } from 'vue'; |
|
import type { GetKey } from '../interface'; |
|
|
|
export type CacheMap = Map<any, number>; |
|
|
|
export default function useHeights<T>( |
|
mergedData: ShallowRef<any[]>, |
|
getKey: GetKey<T>, |
|
onItemAdd?: ((item: T) => void) | null, |
|
onItemRemove?: ((item: T) => void) | null, |
|
): [(item: T, instance: HTMLElement) => void, () => void, CacheMap, Ref<Symbol>] { |
|
const instance = new Map<VNodeProps['key'], HTMLElement>(); |
|
const heights = new Map(); |
|
const updatedMark = ref(Symbol('update')); |
|
watch(mergedData, () => { |
|
updatedMark.value = Symbol('update'); |
|
}); |
|
let heightUpdateId = 0; |
|
function collectHeight() { |
|
heightUpdateId += 1; |
|
const currentId = heightUpdateId; |
|
Promise.resolve().then(() => { |
|
// Only collect when it's latest call |
|
if (currentId !== heightUpdateId) return; |
|
// let changed = false; |
|
instance.forEach((element, key) => { |
|
if (element && element.offsetParent) { |
|
const { offsetHeight } = element; |
|
if (heights.get(key) !== offsetHeight) { |
|
//changed = true; |
|
updatedMark.value = Symbol('update'); |
|
heights.set(key, element.offsetHeight); |
|
} |
|
} |
|
}); |
|
}); |
|
} |
|
|
|
function setInstance(item: T, ins: HTMLElement) { |
|
const key = getKey(item); |
|
const origin = instance.get(key); |
|
|
|
if (ins) { |
|
instance.set(key, (ins as any).$el || ins); |
|
collectHeight(); |
|
} else { |
|
instance.delete(key); |
|
} |
|
|
|
// Instance changed |
|
if (!origin !== !ins) { |
|
if (ins) { |
|
onItemAdd?.(item); |
|
} else { |
|
onItemRemove?.(item); |
|
} |
|
} |
|
} |
|
|
|
return [setInstance, collectHeight, heights, updatedMark]; |
|
}
|
|
|