// @ts-nocheck // #ifdef UNI-APP-X && APP // export * from './uvue.uts' export { getRect, getAllRect } from './uvue.uts' // #endif // #ifndef UNI-APP-X && APP // export * from './vue.ts' export { getRect, getAllRect } from './vue.ts' // #endif /** * 获取视口滚动条位置信息 */ export function getViewportScrollInfo() : Promise { return new Promise(resolve => { uni.createSelectorQuery() .selectViewport() .scrollOffset((res) => { resolve(res); }).exec(); }) } /** ``` page ╱ ╭───────────────╮ viewport ╭─│─ ─ ─ ─ ─ ─ ─ ─│─╮ ╱ │ │ ╭───────────╮ │ │ │ │ │ element │ │ │ │ │ ╰───────────╯ │ │ ╰─│─ ─ ─ ─ ─ ─ ─ ─│─╯ │ │ │ │ ╰───────────────╯ ``` # 参数 - viewportHeight: viewport 高度 - viewportScrollTop: viewport 垂直滚动值 - elementHeight: element 高度 - elementOffsetTop: element 距离页面顶部距离 # 选项 - position: element 在视窗中的位置(start, center, end, nearest) - startOffset: element 距离视窗顶部的偏移量 - endOffset: element 距离视窗底部的偏移量 # 结果值 - viewportScrollTop: viewport 新的垂直滚动值 */ export type ScrollIntoViewOptions = { /** 元素顶部需要保留的缓冲距离(默认 0) */ startOffset ?: number; /** 元素底部需要保留的缓冲距离(默认 0) */ endOffset ?: number; /** 滚动对齐方式:start/center/end/nearest(默认 nearest) */ position ?: 'start' | 'center' | 'end' | 'nearest'; } /** * 计算元素需要滚动到可视区域的目标滚动位置 * @param viewportHeight 视口高度(像素) * @param viewportScrollTop 当前滚动位置(像素) * @param elementHeight 元素高度(像素) * @param elementOffsetTop 元素相对于父容器顶部的偏移量(像素) * @param options 配置选项 * @returns 计算后的目标滚动位置(像素) * * @example * // 示例:将元素滚动到视口顶部对齐 * const scrollTop = getScrollIntoViewValue( * 500, // 视口高度 * 200, // 当前滚动位置 * 100, // 元素高度 * 300, // 元素偏移量 * { position: 'start' } * ); */ export function getScrollIntoViewValue( viewportHeight : number, viewportScrollTop : number, elementHeight : number, elementOffsetTop : number, options : ScrollIntoViewOptions = {} ) : number { let { startOffset = 0, endOffset = 0, position = 'nearest'} = options; // 计算元素相对于视口的上下偏移量 const elementToViewportTopOffset = elementOffsetTop - viewportScrollTop - startOffset; const elementToViewportBottomOffset = elementOffsetTop + elementHeight - viewportScrollTop - viewportHeight + endOffset; // 处理 nearest 模式,自动选择最近边缘 if (position == 'nearest') { if (elementToViewportTopOffset >= 0 && elementToViewportBottomOffset <= 0) { return viewportScrollTop; } position = Math.abs(elementToViewportTopOffset) > Math.abs(elementToViewportBottomOffset) ? 'end' : 'start'; } // 根据不同的对齐位置计算目标滚动位置 let nextScrollTop = 0; switch (position) { case 'start': // 顶部对齐:元素顶部对齐视口顶部(考虑顶部缓冲) nextScrollTop = elementOffsetTop - startOffset; break; case 'center': // 居中对齐:元素中心对齐视口中心(考虑上下缓冲) nextScrollTop = elementOffsetTop - (viewportHeight - elementHeight - endOffset - startOffset) / 2 + startOffset; break; case 'end': // 底部对齐:元素底部对齐视口底部(考虑底部缓冲) nextScrollTop = elementOffsetTop + elementHeight - viewportHeight + endOffset; break; } return nextScrollTop; }