import type { FormRenderProps } from '../types';
|
|
import { computed, nextTick, onMounted, ref, useTemplateRef, watch } from 'vue';
|
|
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core';
|
|
/**
|
* 动态计算行数
|
*/
|
export function useExpandable(props: FormRenderProps) {
|
const wrapperRef = useTemplateRef<HTMLElement>('wrapperRef');
|
const rowMapping = ref<Record<number, number>>({});
|
// 是否已经计算过一次
|
const isCalculated = ref(false);
|
|
const breakpoints = useBreakpoints(breakpointsTailwind);
|
|
const keepFormItemIndex = computed(() => {
|
const rows = props.collapsedRows ?? 1;
|
const mapping = rowMapping.value;
|
let maxItem = 0;
|
for (let index = 1; index <= rows; index++) {
|
maxItem += mapping?.[index] ?? 0;
|
}
|
// 保持一行
|
return maxItem - 1 || 1;
|
});
|
|
watch(
|
[
|
() => props.showCollapseButton,
|
() => breakpoints.active().value,
|
() => props.schema?.length,
|
],
|
async ([val]) => {
|
if (val) {
|
await nextTick();
|
rowMapping.value = {};
|
isCalculated.value = false;
|
await calculateRowMapping();
|
}
|
},
|
);
|
|
async function calculateRowMapping() {
|
if (!props.showCollapseButton) {
|
return;
|
}
|
|
await nextTick();
|
if (!wrapperRef.value) {
|
return;
|
}
|
// 小屏幕不计算
|
// if (breakpoints.smaller('sm').value) {
|
// // 保持一行
|
// rowMapping.value = { 1: 2 };
|
// return;
|
// }
|
|
const formItems = [...wrapperRef.value.children];
|
|
const container = wrapperRef.value;
|
const containerStyles = window.getComputedStyle(container);
|
const rowHeights = containerStyles
|
.getPropertyValue('grid-template-rows')
|
.split(' ');
|
|
const containerRect = container?.getBoundingClientRect();
|
|
formItems.forEach((el) => {
|
const itemRect = el.getBoundingClientRect();
|
|
// 计算元素在第几行
|
const itemTop = itemRect.top - containerRect.top;
|
let rowStart = 0;
|
let cumulativeHeight = 0;
|
|
for (const [i, rowHeight] of rowHeights.entries()) {
|
cumulativeHeight += Number.parseFloat(rowHeight);
|
if (itemTop < cumulativeHeight) {
|
rowStart = i + 1;
|
break;
|
}
|
}
|
if (rowStart > (props?.collapsedRows ?? 1)) {
|
return;
|
}
|
rowMapping.value[rowStart] = (rowMapping.value[rowStart] ?? 0) + 1;
|
isCalculated.value = true;
|
});
|
}
|
|
onMounted(() => {
|
calculateRowMapping();
|
});
|
|
return { isCalculated, keepFormItemIndex, wrapperRef };
|
}
|