index.ts
3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// @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<any> {
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;
}