/** * 浮动面板锚点:合并集合并按规则吸附到合法 height(无 Vue 依赖,便于测试与复用)。 */ export type AnchorsSnapResult = { anchors: number[]; height: number }; /** * 根据新锚点候选合并列表,并计算吸附后的 `height`。 * @param values - 本次写入的锚点(或单个) * @param reset - 为 `true` 时以 `values` 为基底;为 `false` 时与 `currentAnchors` 合并 * @param prevHeight - 吸附前的面板总高度 * @param maxContainerHeight - 允许的最大总高度(px) * @param currentAnchors - 当前 v-model 锚点(`reset === false` 时参与合并) */ export function computeAnchorsAndSnapHeight( values: number | number[], reset: boolean, prevHeight: number, maxContainerHeight: number, currentAnchors: readonly number[], ): AnchorsSnapResult | null { const list = !Array.isArray(values) ? [values] : values; const set = new Set(list); if (!reset) currentAnchors.forEach((a) => set.add(a)); const anchors = [...set].filter((v) => v <= maxContainerHeight).sort((a, b) => a - b); if (!anchors.length) return null; const hit = anchors.findIndex((v) => v === prevHeight); if (hit >= 0) { return { anchors, height: anchors[hit]! }; } let nearest = anchors[0]!; let minDist = Math.abs(prevHeight - nearest); for (const a of anchors) { const d = Math.abs(prevHeight - a); if (d < minDist) { minDist = d; nearest = a; } } const positives = anchors.filter((a) => a > 0); if (nearest === 0 && prevHeight > 0 && positives.length) { const height = positives.reduce((m, a) => (Math.abs(a - prevHeight) < Math.abs(m - prevHeight) ? a : m)); return { anchors, height }; } return { anchors, height: nearest }; }