hy-app 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -1
- package/attributes.json +1 -1
- package/components/hy-list/hy-list.vue +360 -228
- package/components/hy-list/index.scss +0 -1
- package/components/hy-list/props.ts +69 -69
- package/components/hy-modal/props.ts +1 -1
- package/components/hy-modal/typing.d.ts +52 -16
- package/components/hy-number-step/hy-number-step.vue +1 -3
- package/libs/common/versionControl.ts +286 -102
- package/package.json +1 -1
- package/web-types.json +1 -1
- package/libs/composables/useTouch.md +0 -237
|
@@ -1,228 +1,360 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<scroll-view
|
|
3
|
-
ref="hyVirtualContainer"
|
|
4
|
-
@scroll="onScroll"
|
|
5
|
-
@scrolltolower="scrollToLower"
|
|
6
|
-
:lower-threshold="showDivider ? 100 : 50"
|
|
7
|
-
:scroll-y="true"
|
|
8
|
-
scroll-with-animation
|
|
9
|
-
class="hy-virtual-container"
|
|
10
|
-
>
|
|
11
|
-
<view class="hy-virtual-container__list">
|
|
12
|
-
<slot v-if="slotDefault" :record="line === 1 ? virtualData : waterfall"></slot>
|
|
13
|
-
<template v-else>
|
|
14
|
-
<view
|
|
15
|
-
v-if="line === 1"
|
|
16
|
-
class="hy-virtual-container__list--item"
|
|
17
|
-
v-for="(item, i) in virtualData"
|
|
18
|
-
:key="typeof item === 'string' ? i : item[keyField]"
|
|
19
|
-
:style="itemStyle"
|
|
20
|
-
@click="handleClick(item)"
|
|
21
|
-
>
|
|
22
|
-
<slot style="height: 100%" name="content" :record="item"></slot>
|
|
23
|
-
</view>
|
|
24
|
-
|
|
25
|
-
<view
|
|
26
|
-
v-if="line === 2"
|
|
27
|
-
class="hy-virtual-container__list--left hy-virtual-container__list--box"
|
|
28
|
-
>
|
|
29
|
-
<view
|
|
30
|
-
v-if="slots.left"
|
|
31
|
-
class="hy-virtual-container__list--box-item"
|
|
32
|
-
v-for="item in waterfall.left"
|
|
33
|
-
:key="item[keyField]"
|
|
34
|
-
:style="itemStyle"
|
|
35
|
-
@click="handleClick(item)"
|
|
36
|
-
>
|
|
37
|
-
<slot name="left" :record="item"></slot>
|
|
38
|
-
</view>
|
|
39
|
-
<slot v-else name="left-list" :record="waterfall.left"></slot>
|
|
40
|
-
</view>
|
|
41
|
-
<view
|
|
42
|
-
v-if="line === 2"
|
|
43
|
-
class="hy-virtual-container__list--right hy-virtual-container__list--box"
|
|
44
|
-
>
|
|
45
|
-
<view
|
|
46
|
-
v-if="slots.right"
|
|
47
|
-
class="hy-virtual-container__list--box-item"
|
|
48
|
-
v-for="item in waterfall.right"
|
|
49
|
-
:key="item[keyField]"
|
|
50
|
-
:style="itemStyle"
|
|
51
|
-
@click="handleClick(item)"
|
|
52
|
-
>
|
|
53
|
-
<slot name="right" :record="item"></slot>
|
|
54
|
-
</view>
|
|
55
|
-
<slot v-else name="right-list" :record="waterfall.right"></slot>
|
|
56
|
-
</view>
|
|
57
|
-
</template>
|
|
58
|
-
<!--加载更多样式-->
|
|
59
|
-
</view>
|
|
60
|
-
<slot v-if="$slots.footer" name="footer"></slot>
|
|
61
|
-
<hy-divider :text="load" v-else-if="showDivider"></hy-divider>
|
|
62
|
-
</scroll-view>
|
|
63
|
-
</template>
|
|
64
|
-
|
|
65
|
-
<script lang="ts">
|
|
66
|
-
export default {
|
|
67
|
-
name: 'hy-list',
|
|
68
|
-
options: {
|
|
69
|
-
addGlobalClass: true,
|
|
70
|
-
virtualHost: true,
|
|
71
|
-
styleIsolation: 'shared'
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
</script>
|
|
75
|
-
|
|
76
|
-
<script lang="ts" setup>
|
|
77
|
-
import {
|
|
78
|
-
computed,
|
|
79
|
-
getCurrentInstance,
|
|
80
|
-
nextTick,
|
|
81
|
-
onMounted,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
import {
|
|
89
|
-
import
|
|
90
|
-
import
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
*
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const
|
|
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
|
-
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
*
|
|
151
|
-
*/
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<scroll-view
|
|
3
|
+
ref="hyVirtualContainer"
|
|
4
|
+
@scroll="onScroll"
|
|
5
|
+
@scrolltolower="scrollToLower"
|
|
6
|
+
:lower-threshold="showDivider ? 100 : 50"
|
|
7
|
+
:scroll-y="true"
|
|
8
|
+
scroll-with-animation
|
|
9
|
+
class="hy-virtual-container"
|
|
10
|
+
>
|
|
11
|
+
<view class="hy-virtual-container__list">
|
|
12
|
+
<slot v-if="slotDefault" :record="line === 1 ? virtualData : waterfall"></slot>
|
|
13
|
+
<template v-else>
|
|
14
|
+
<view
|
|
15
|
+
v-if="line === 1"
|
|
16
|
+
class="hy-virtual-container__list--item"
|
|
17
|
+
v-for="(item, i) in virtualData"
|
|
18
|
+
:key="typeof item === 'string' ? i : item[keyField]"
|
|
19
|
+
:style="itemStyle"
|
|
20
|
+
@click="handleClick(item)"
|
|
21
|
+
>
|
|
22
|
+
<slot style="height: 100%" name="content" :record="item"></slot>
|
|
23
|
+
</view>
|
|
24
|
+
|
|
25
|
+
<view
|
|
26
|
+
v-if="line === 2"
|
|
27
|
+
class="hy-virtual-container__list--left hy-virtual-container__list--box"
|
|
28
|
+
>
|
|
29
|
+
<view
|
|
30
|
+
v-if="slots.left"
|
|
31
|
+
class="hy-virtual-container__list--box-item"
|
|
32
|
+
v-for="item in waterfall.left"
|
|
33
|
+
:key="item[keyField]"
|
|
34
|
+
:style="itemStyle"
|
|
35
|
+
@click="handleClick(item)"
|
|
36
|
+
>
|
|
37
|
+
<slot name="left" :record="item"></slot>
|
|
38
|
+
</view>
|
|
39
|
+
<slot v-else name="left-list" :record="waterfall.left"></slot>
|
|
40
|
+
</view>
|
|
41
|
+
<view
|
|
42
|
+
v-if="line === 2"
|
|
43
|
+
class="hy-virtual-container__list--right hy-virtual-container__list--box"
|
|
44
|
+
>
|
|
45
|
+
<view
|
|
46
|
+
v-if="slots.right"
|
|
47
|
+
class="hy-virtual-container__list--box-item"
|
|
48
|
+
v-for="item in waterfall.right"
|
|
49
|
+
:key="item[keyField]"
|
|
50
|
+
:style="itemStyle"
|
|
51
|
+
@click="handleClick(item)"
|
|
52
|
+
>
|
|
53
|
+
<slot name="right" :record="item"></slot>
|
|
54
|
+
</view>
|
|
55
|
+
<slot v-else name="right-list" :record="waterfall.right"></slot>
|
|
56
|
+
</view>
|
|
57
|
+
</template>
|
|
58
|
+
<!--加载更多样式-->
|
|
59
|
+
</view>
|
|
60
|
+
<slot v-if="$slots.footer" name="footer"></slot>
|
|
61
|
+
<hy-divider :text="load" v-else-if="showDivider"></hy-divider>
|
|
62
|
+
</scroll-view>
|
|
63
|
+
</template>
|
|
64
|
+
|
|
65
|
+
<script lang="ts">
|
|
66
|
+
export default {
|
|
67
|
+
name: 'hy-list',
|
|
68
|
+
options: {
|
|
69
|
+
addGlobalClass: true,
|
|
70
|
+
virtualHost: true,
|
|
71
|
+
styleIsolation: 'shared'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<script lang="ts" setup>
|
|
77
|
+
import {
|
|
78
|
+
computed,
|
|
79
|
+
getCurrentInstance,
|
|
80
|
+
nextTick,
|
|
81
|
+
onMounted,
|
|
82
|
+
onUnmounted,
|
|
83
|
+
reactive,
|
|
84
|
+
ref,
|
|
85
|
+
useSlots,
|
|
86
|
+
watch
|
|
87
|
+
} from 'vue'
|
|
88
|
+
import type { CSSProperties } from 'vue'
|
|
89
|
+
import { addUnit, getPx, getRect, throttle } from '../../libs'
|
|
90
|
+
import type { IListEmits } from './typing'
|
|
91
|
+
import listProps from './props'
|
|
92
|
+
// 组件
|
|
93
|
+
import HyDivider from '../hy-divider/hy-divider.vue'
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 实现只展示可视内容的dom,减少dom创建,优化滚动性能
|
|
97
|
+
* @displayName hy-list
|
|
98
|
+
*/
|
|
99
|
+
defineOptions({})
|
|
100
|
+
|
|
101
|
+
const props = defineProps(listProps)
|
|
102
|
+
const emit = defineEmits<IListEmits>()
|
|
103
|
+
|
|
104
|
+
const slots = useSlots()
|
|
105
|
+
// 滚动容器引用
|
|
106
|
+
const hyVirtualContainer = ref<UniApp.NodeInfo | null>(null)
|
|
107
|
+
// 滚动条距离顶部距离
|
|
108
|
+
const scrollTop = ref(0)
|
|
109
|
+
// 可视区域的高度
|
|
110
|
+
const viewHeight = ref(0)
|
|
111
|
+
// 瀑布流数据
|
|
112
|
+
const waterfall: {
|
|
113
|
+
left: AnyObject[]
|
|
114
|
+
right: AnyObject[]
|
|
115
|
+
} = reactive({
|
|
116
|
+
left: [],
|
|
117
|
+
right: []
|
|
118
|
+
})
|
|
119
|
+
// 排列方式
|
|
120
|
+
const arrange = computed(() => (props.line === 1 ? 'column' : 'row'))
|
|
121
|
+
const listHeight = addUnit(props.containerHeight)
|
|
122
|
+
const instance = getCurrentInstance()
|
|
123
|
+
// 高度缓存映射表(支持动态高度)
|
|
124
|
+
const heightCache = reactive<Record<number, number>>({})
|
|
125
|
+
// 预估高度(用于首屏渲染)
|
|
126
|
+
const estimatedHeight = computed(() => getPx(props.itemHeight) + getPx(props.marginBottom))
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 节流函数(返回新函数版本)
|
|
130
|
+
*/
|
|
131
|
+
const throttleFn = <T extends (...args: any[]) => void>(fn: T, wait: number = 16): T => {
|
|
132
|
+
let lastTime = 0
|
|
133
|
+
return ((...args: any[]) => {
|
|
134
|
+
const now = Date.now()
|
|
135
|
+
if (now - lastTime >= wait) {
|
|
136
|
+
lastTime = now
|
|
137
|
+
fn(...args)
|
|
138
|
+
}
|
|
139
|
+
}) as T
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
onMounted(() => {
|
|
143
|
+
nextTick(async () => {
|
|
144
|
+
const res = await getRect('.hy-virtual-container', false, instance)
|
|
145
|
+
viewHeight.value = (res as UniApp.NodeInfo).height || 0
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 获取指定索引的实际高度(优先从缓存获取)
|
|
151
|
+
*/
|
|
152
|
+
const getItemHeight = (index: number): number => {
|
|
153
|
+
return heightCache[index] ?? estimatedHeight.value
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 计算从0到指定索引的累计高度
|
|
158
|
+
*/
|
|
159
|
+
const getCumulativeHeight = (endIndex: number): number => {
|
|
160
|
+
let total = 0
|
|
161
|
+
for (let i = 0; i < endIndex && i < props.list.length; i++) {
|
|
162
|
+
total += getItemHeight(i)
|
|
163
|
+
}
|
|
164
|
+
return total
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 计算虚拟列表的总高度
|
|
169
|
+
*/
|
|
170
|
+
const totalHeight = computed(() => {
|
|
171
|
+
return getCumulativeHeight(props.list.length)
|
|
172
|
+
})
|
|
173
|
+
const itemStyle = computed((): CSSProperties => {
|
|
174
|
+
return {
|
|
175
|
+
height: addUnit(props.itemHeight),
|
|
176
|
+
padding: addUnit(props.padding),
|
|
177
|
+
marginBottom: addUnit(props.marginBottom),
|
|
178
|
+
borderRadius: addUnit(props.borderRadius),
|
|
179
|
+
background: props.background,
|
|
180
|
+
border: props.border ? '1px solid #dadbde' : ''
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 虚拟列表真实展示数据:起始下标(支持动态高度)
|
|
186
|
+
*/
|
|
187
|
+
const start = computed(() => {
|
|
188
|
+
if (props.list.length === 0) return 0
|
|
189
|
+
|
|
190
|
+
let cumulativeHeight = 0
|
|
191
|
+
let startIndex = 0
|
|
192
|
+
|
|
193
|
+
// 向后查找第一个累计高度超过scrollTop的位置
|
|
194
|
+
for (let i = 0; i < props.list.length; i++) {
|
|
195
|
+
cumulativeHeight += getItemHeight(i)
|
|
196
|
+
if (cumulativeHeight > scrollTop.value) {
|
|
197
|
+
startIndex = i
|
|
198
|
+
break
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 向上多取几个作为缓冲,避免快速滚动时出现空白
|
|
203
|
+
const buffer = props.line * 2
|
|
204
|
+
return Math.max(0, startIndex - buffer)
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* 虚拟列表真实展示数据:结束下标(支持动态高度)
|
|
209
|
+
*/
|
|
210
|
+
const over = computed(() => {
|
|
211
|
+
if (props.list.length === 0) return 0
|
|
212
|
+
|
|
213
|
+
const targetHeight = scrollTop.value + viewHeight.value + 100 // 额外缓冲高度
|
|
214
|
+
let cumulativeHeight = 0
|
|
215
|
+
|
|
216
|
+
// 从start开始查找第一个累计高度超过targetHeight的位置
|
|
217
|
+
for (let i = start.value; i < props.list.length; i++) {
|
|
218
|
+
cumulativeHeight += getItemHeight(i)
|
|
219
|
+
if (cumulativeHeight > targetHeight) {
|
|
220
|
+
// 多取几个作为缓冲
|
|
221
|
+
return Math.min(props.list.length, i + props.line * 2)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return props.list.length
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* 计算虚拟列表的padding(保持列表高度完整且滚动条能正常滚动)
|
|
230
|
+
*/
|
|
231
|
+
const paddingAttr = computed(() => {
|
|
232
|
+
const paddingTop = getCumulativeHeight(start.value)
|
|
233
|
+
const paddingBottom = Math.max(0, totalHeight.value - getCumulativeHeight(over.value))
|
|
234
|
+
return `${paddingTop}px 0 ${paddingBottom}px`
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* 虚拟列表真实展示数据
|
|
239
|
+
*/
|
|
240
|
+
const virtualData = computed<(string | Record<string, any>)[]>(() => {
|
|
241
|
+
return props.list.slice(start.value, over.value)
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 更新瀑布流数据
|
|
246
|
+
*/
|
|
247
|
+
const updateWaterfall = (data: (string | Record<string, any>)[]) => {
|
|
248
|
+
// 使用splice替代length=0,性能更好
|
|
249
|
+
waterfall.left.splice(0, waterfall.left.length)
|
|
250
|
+
waterfall.right.splice(0, waterfall.right.length)
|
|
251
|
+
|
|
252
|
+
if (props.line === 2 && data.length > 0 && typeof data[0] !== 'string') {
|
|
253
|
+
// 优化:使用push批量添加
|
|
254
|
+
const leftItems: AnyObject[] = []
|
|
255
|
+
const rightItems: AnyObject[] = []
|
|
256
|
+
|
|
257
|
+
for (let i = 0; i < data.length; i++) {
|
|
258
|
+
if (i % 2 === 0) {
|
|
259
|
+
leftItems.push(data[i] as AnyObject)
|
|
260
|
+
} else {
|
|
261
|
+
rightItems.push(data[i] as AnyObject)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
waterfall.left.push(...leftItems)
|
|
266
|
+
waterfall.right.push(...rightItems)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
watch(
|
|
271
|
+
() => virtualData.value,
|
|
272
|
+
(newVal) => {
|
|
273
|
+
updateWaterfall(newVal)
|
|
274
|
+
},
|
|
275
|
+
{ immediate: true }
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* 监听滚动条距离顶部距离,实时更新(带节流)
|
|
280
|
+
*/
|
|
281
|
+
const onScroll = throttleFn((e: any) => {
|
|
282
|
+
scrollTop.value = e.detail.scrollTop || 0
|
|
283
|
+
}, 16)
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* 滚动底部函数
|
|
287
|
+
* */
|
|
288
|
+
const scrollToLower = () => {
|
|
289
|
+
emit('scrollToLower')
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* 点击行触发函数
|
|
294
|
+
* */
|
|
295
|
+
const handleClick = (temp: string | AnyObject) => {
|
|
296
|
+
emit('click', temp)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* 获取默认插槽
|
|
301
|
+
*/
|
|
302
|
+
const slotDefault = useSlots().default
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* 滚动到指定索引位置
|
|
306
|
+
* @param index 目标索引
|
|
307
|
+
* @param offset 偏移量(可选)
|
|
308
|
+
*/
|
|
309
|
+
const scrollToIndex = (index: number, offset: number = 0) => {
|
|
310
|
+
if (index < 0 || index >= props.list.length) {
|
|
311
|
+
console.warn(`hy-list: scrollToIndex index ${index} out of bounds`)
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const scrollPosition = getCumulativeHeight(index) + offset
|
|
316
|
+
uni.createSelectorQuery().select('.hy-virtual-container').scrollIntoView({
|
|
317
|
+
scrollTop: scrollPosition,
|
|
318
|
+
duration: 300
|
|
319
|
+
})
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* 滚动到顶部
|
|
324
|
+
*/
|
|
325
|
+
const scrollToTop = () => {
|
|
326
|
+
uni.createSelectorQuery().select('.hy-virtual-container').scrollIntoView({
|
|
327
|
+
scrollTop: 0,
|
|
328
|
+
duration: 300
|
|
329
|
+
})
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* 刷新高度缓存(当列表内容变化时调用)
|
|
334
|
+
*/
|
|
335
|
+
const refreshHeightCache = () => {
|
|
336
|
+
// 清除缓存,下次渲染时重新计算
|
|
337
|
+
Object.keys(heightCache).forEach((key) => {
|
|
338
|
+
delete heightCache[parseInt(key)]
|
|
339
|
+
})
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// 暴露方法给父组件
|
|
343
|
+
defineExpose({
|
|
344
|
+
scrollToIndex,
|
|
345
|
+
scrollToTop,
|
|
346
|
+
refreshHeightCache
|
|
347
|
+
})
|
|
348
|
+
</script>
|
|
349
|
+
|
|
350
|
+
<style lang="scss" scoped>
|
|
351
|
+
@import './index.scss';
|
|
352
|
+
.hy-virtual-container {
|
|
353
|
+
height: v-bind(listHeight);
|
|
354
|
+
&__list {
|
|
355
|
+
padding: v-bind(paddingAttr);
|
|
356
|
+
display: flex;
|
|
357
|
+
flex-direction: v-bind(arrange);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
</style>
|