2022-03-18 08:55:15 +00:00
|
|
|
import type { VNodeProps, Ref, ShallowRef } from 'vue';
|
2023-04-21 03:12:45 +00:00
|
|
|
import { onUnmounted, watch, ref } from 'vue';
|
2021-06-26 01:35:40 +00:00
|
|
|
import type { GetKey } from '../interface';
|
2023-04-21 03:12:45 +00:00
|
|
|
import wrapperRaf from '../../_util/raf';
|
2020-09-28 11:14:00 +00:00
|
|
|
|
2022-03-18 08:55:15 +00:00
|
|
|
export type CacheMap = Map<any, number>;
|
2020-10-01 09:20:10 +00:00
|
|
|
|
|
|
|
export default function useHeights<T>(
|
2022-03-18 08:55:15 +00:00
|
|
|
mergedData: ShallowRef<any[]>,
|
2020-10-01 09:20:10 +00:00
|
|
|
getKey: GetKey<T>,
|
|
|
|
onItemAdd?: ((item: T) => void) | null,
|
|
|
|
onItemRemove?: ((item: T) => void) | null,
|
2021-12-04 16:15:53 +00:00
|
|
|
): [(item: T, instance: HTMLElement) => void, () => void, CacheMap, Ref<Symbol>] {
|
2020-10-01 09:20:10 +00:00
|
|
|
const instance = new Map<VNodeProps['key'], HTMLElement>();
|
2022-04-06 07:53:09 +00:00
|
|
|
const heights = new Map();
|
2021-12-04 16:15:53 +00:00
|
|
|
const updatedMark = ref(Symbol('update'));
|
|
|
|
watch(mergedData, () => {
|
|
|
|
updatedMark.value = Symbol('update');
|
|
|
|
});
|
2023-04-21 03:12:45 +00:00
|
|
|
let collectRaf: number = undefined;
|
|
|
|
|
|
|
|
function cancelRaf() {
|
|
|
|
wrapperRaf.cancel(collectRaf);
|
|
|
|
}
|
2020-09-28 11:14:00 +00:00
|
|
|
function collectHeight() {
|
2023-04-21 03:12:45 +00:00
|
|
|
cancelRaf();
|
|
|
|
collectRaf = wrapperRaf(() => {
|
2020-09-28 11:14:00 +00:00
|
|
|
instance.forEach((element, key) => {
|
|
|
|
if (element && element.offsetParent) {
|
2020-10-01 09:20:10 +00:00
|
|
|
const { offsetHeight } = element;
|
2022-03-18 08:55:15 +00:00
|
|
|
if (heights.get(key) !== offsetHeight) {
|
2020-10-18 09:37:52 +00:00
|
|
|
//changed = true;
|
2021-12-04 16:15:53 +00:00
|
|
|
updatedMark.value = Symbol('update');
|
2022-03-18 08:55:15 +00:00
|
|
|
heights.set(key, element.offsetHeight);
|
2020-09-28 11:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-10-01 09:20:10 +00:00
|
|
|
function setInstance(item: T, ins: HTMLElement) {
|
2020-09-28 11:14:00 +00:00
|
|
|
const key = getKey(item);
|
|
|
|
const origin = instance.get(key);
|
|
|
|
|
|
|
|
if (ins) {
|
2021-09-25 08:51:32 +00:00
|
|
|
instance.set(key, (ins as any).$el || ins);
|
2020-09-28 11:14:00 +00:00
|
|
|
collectHeight();
|
|
|
|
} else {
|
|
|
|
instance.delete(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instance changed
|
|
|
|
if (!origin !== !ins) {
|
|
|
|
if (ins) {
|
|
|
|
onItemAdd?.(item);
|
|
|
|
} else {
|
|
|
|
onItemRemove?.(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-04-21 03:12:45 +00:00
|
|
|
onUnmounted(() => {
|
|
|
|
cancelRaf();
|
|
|
|
});
|
2020-09-28 11:14:00 +00:00
|
|
|
|
2021-12-04 16:15:53 +00:00
|
|
|
return [setInstance, collectHeight, heights, updatedMark];
|
2020-09-28 11:14:00 +00:00
|
|
|
}
|