import type { VNodeProps, Ref, ShallowRef } from 'vue'; import { onUnmounted, watch, ref } from 'vue'; import type { GetKey } from '../interface'; import wrapperRaf from '../../_util/raf'; export type CacheMap = Map; export default function useHeights( mergedData: ShallowRef, getKey: GetKey, onItemAdd?: ((item: T) => void) | null, onItemRemove?: ((item: T) => void) | null, ): [(item: T, instance: HTMLElement) => void, () => void, CacheMap, Ref] { const instance = new Map(); const heights = new Map(); const updatedMark = ref(Symbol('update')); watch(mergedData, () => { updatedMark.value = Symbol('update'); }); let collectRaf: number = undefined; function cancelRaf() { wrapperRaf.cancel(collectRaf); } function collectHeight() { cancelRaf(); collectRaf = wrapperRaf(() => { 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); } } } onUnmounted(() => { cancelRaf(); }); return [setInstance, collectHeight, heights, updatedMark]; }