oxy-uni-ui 1.1.0 → 1.2.0

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.
@@ -642,6 +642,7 @@ $-tag-close-color: var(--oxy-tag-close-color, $-tag-info-color) !default; // 关
642
642
  $-tag-close-active-color: var(--oxy-tag-close-active-color, rgba(0, 0, 0, 0.45)) !default; // 关闭按钮 active 颜色
643
643
 
644
644
  /* corner */
645
+ $-corner-radius: var(--oxy-corner-radius, 12px) !default; // 圆角大小
645
646
  $-corner-font-size: var(--oxy-corner-fs, $-fs-secondary) !default; // 字号
646
647
  $-corner-font-weight: var(--oxy-corner-fs, 400) !default; // 字号
647
648
  $-corner-color: var(--oxy-corner-color, $-color-white) !default; // 字体颜色
@@ -662,6 +663,13 @@ $-corner-horizontal-info-bg: var(--oxy-corner-info-bg, resultColor(90deg, $-colo
662
663
  $-corner-horizontal-success-bg: var(--oxy-corner-success-bg, resultColor(90deg, $-color-success, 'light' 'dark', #ffffff #b2ebcf, 0% 100%)) !default; // success 背景颜色
663
664
  $-corner-horizontal-warning-bg: var(--oxy-corner-warning-bg, resultColor(90deg, $-color-warning, 'light' 'dark', #ffffff #fcedd6, 0% 100%)) !default; // warning 背景颜色
664
665
  $-corner-horizontal-danger-bg: var(--oxy-corner-danger-bg, resultColor(90deg, $-color-danger, 'light' 'dark', #ffffff #ffd5d8, 0% 100%)) !default; // danger 背景颜色
666
+ $-corner-embedded-font-size: var(--oxy-corner-fs, $-fs-content) !default; // 字号
667
+ $-corner-embedded-font-weight: var(--oxy-corner-fs, 400) !default; // 字号
668
+ $-corner-embedded-primary-bg: var(--oxy-corner-primary-bg, #cceaff) !default; // 主背景颜色
669
+ $-corner-embedded-info-bg: var(--oxy-corner-info-bg, #eef4fc) !default; // info 背景颜色
670
+ $-corner-embedded-success-bg: var(--oxy-corner-success-bg, #b2ebcf) !default; // success 背景颜色
671
+ $-corner-embedded-warning-bg: var(--oxy-corner-warning-bg, #fcedd6) !default; // warning 背景颜色
672
+ $-corner-embedded-danger-bg: var(--oxy-corner-danger-bg, #ffd5d8) !default; // danger 背景颜色
665
673
 
666
674
  /* toast */
667
675
  $-toast-color: var(--oxy-toast-color, $-color-white) !default; // 文字颜色
@@ -9,3 +9,4 @@ export { useRaf } from './useRaf'
9
9
  export { useTouch } from './useTouch'
10
10
  export { useTranslate } from './useTranslate'
11
11
  export { useUpload } from './useUpload'
12
+ export { useVirtualScroll } from './useVirtualScroll'
@@ -0,0 +1,172 @@
1
+ /**
2
+ * 虚拟滚动组合式函数 - 用于复用虚拟滚动逻辑
3
+ */
4
+
5
+ import { ref, computed, watch, nextTick, type Ref } from 'vue'
6
+ import { VirtualScrollEngine } from '../oxy-virtual-scroll/virtual-scroll'
7
+
8
+ export interface UseVirtualScrollOptions {
9
+ data: Ref<any[]>
10
+ virtual: Ref<boolean>
11
+ height: Ref<string>
12
+ itemHeight: Ref<string>
13
+ idKey: Ref<string>
14
+ backToTopThreshold: Ref<string>
15
+ }
16
+
17
+ export interface UseVirtualScrollReturn {
18
+ // 响应式数据
19
+ scrollTop: Ref<number>
20
+ showBackTopBtn: Ref<boolean>
21
+ virtualData: Ref<any[]>
22
+ startIndex: Ref<number>
23
+ virtualOffsetY: Ref<number>
24
+ totalHeight: Ref<number>
25
+ displayData: Ref<any[]>
26
+
27
+ // 方法
28
+ initScrollData: () => void
29
+ initScrollEngine: () => void
30
+ updateVisibleData: () => void
31
+ scrollToTop: () => void
32
+ scrollToBottom: () => void
33
+ scrollToPosition: (position: number | string) => void
34
+ scrollToElement: (item: any) => void
35
+ scrollToElementById: (id: string | number) => void
36
+ onScroll: (scrollTopValue: number) => void
37
+ }
38
+
39
+ export function useVirtualScroll(options: UseVirtualScrollOptions): UseVirtualScrollReturn {
40
+ const { data, virtual, height, itemHeight, idKey, backToTopThreshold } = options
41
+
42
+ // 响应式数据
43
+ const scrollTop = ref<number>(0)
44
+ const showBackTopBtn = ref<boolean>(false)
45
+ const virtualData = ref<any[]>([])
46
+ const startIndex = ref<number>(0)
47
+ const virtualOffsetY = ref<number>(0)
48
+ const virtualEngine = ref<any>(null)
49
+
50
+ // 计算属性
51
+ const displayData = computed<any[]>(() => data.value)
52
+
53
+ const totalHeight = computed(() => {
54
+ return displayData.value.length * parseFloat(itemHeight.value)
55
+ })
56
+
57
+ // 监听数据变化
58
+ watch(
59
+ () => data.value,
60
+ () => {
61
+ nextTick(initScrollData)
62
+ },
63
+ {
64
+ immediate: true,
65
+ deep: true
66
+ }
67
+ )
68
+
69
+ // 初始化滚动数据
70
+ function initScrollData() {
71
+ if (!virtual.value) {
72
+ // 非虚拟滚动模式:直接使用全部数据
73
+ virtualData.value = displayData.value
74
+ virtualOffsetY.value = 0
75
+ return
76
+ }
77
+
78
+ virtualEngine.value = new VirtualScrollEngine({
79
+ containerHeight: parseFloat(height.value),
80
+ itemHeight: parseFloat(itemHeight.value),
81
+ data: displayData.value
82
+ })
83
+ updateVisibleData()
84
+ }
85
+
86
+ // 初始化滚动引擎
87
+ function initScrollEngine() {
88
+ if (!virtual.value) return
89
+
90
+ virtualEngine.value = new VirtualScrollEngine({
91
+ containerHeight: parseFloat(height.value),
92
+ itemHeight: parseFloat(itemHeight.value),
93
+ data: displayData.value
94
+ })
95
+ }
96
+
97
+ // 更新可见数据
98
+ function updateVisibleData() {
99
+ if (!virtual.value) return // 非虚拟模式不处理
100
+
101
+ if (virtualEngine.value) {
102
+ const { visibleData, offsetY } = virtualEngine.value.updateVisibleData(scrollTop.value || 0)
103
+ virtualData.value = visibleData
104
+ virtualOffsetY.value = offsetY
105
+ }
106
+ }
107
+
108
+ // 滚动事件处理
109
+ function onScroll(scrollTopValue: number) {
110
+ scrollTop.value = scrollTopValue
111
+ showBackTopBtn.value = scrollTopValue > parseFloat(backToTopThreshold.value)
112
+ updateVisibleData()
113
+ }
114
+
115
+ // 滚动到顶部
116
+ function scrollToTop() {
117
+ scrollTop.value = 0
118
+ nextTick(() => {
119
+ scrollTop.value = 0
120
+ })
121
+ }
122
+
123
+ // 滚动到底部
124
+ function scrollToBottom() {
125
+ scrollToPosition(totalHeight.value)
126
+ }
127
+
128
+ // 滚动到指定位置
129
+ function scrollToPosition(position: number | string) {
130
+ scrollTop.value = typeof position === 'number' ? position : parseFloat(position)
131
+ }
132
+
133
+ // 滚动到指定元素
134
+ function scrollToElement(item: any) {
135
+ const index = data.value.findIndex((o) => item[idKey.value] && o[idKey.value] && o[idKey.value] === item[idKey.value])
136
+ if (index > 0) {
137
+ const scrollDistance = parseFloat(itemHeight.value) * index
138
+ scrollToPosition(scrollDistance)
139
+ }
140
+ }
141
+
142
+ // 根据ID滚动到指定元素
143
+ function scrollToElementById(id: string | number) {
144
+ const index = data.value.findIndex((o) => id && o[idKey.value] && o[idKey.value] === id)
145
+ if (index > 0) {
146
+ const scrollDistance = parseFloat(itemHeight.value) * index
147
+ scrollToPosition(scrollDistance)
148
+ }
149
+ }
150
+
151
+ return {
152
+ // 响应式数据
153
+ scrollTop,
154
+ showBackTopBtn,
155
+ virtualData,
156
+ startIndex,
157
+ virtualOffsetY,
158
+ totalHeight,
159
+ displayData,
160
+
161
+ // 方法
162
+ initScrollData,
163
+ initScrollEngine,
164
+ updateVisibleData,
165
+ scrollToTop,
166
+ scrollToBottom,
167
+ scrollToPosition,
168
+ scrollToElement,
169
+ scrollToElementById,
170
+ onScroll
171
+ }
172
+ }
@@ -14,6 +14,9 @@
14
14
  width: 80px;
15
15
  height: 80px;
16
16
  overflow: hidden;
17
+ @include when(round) {
18
+ border-top-right-radius: $-corner-radius;
19
+ }
17
20
  @include when(primary) {
18
21
  .oxy-corner__text {
19
22
  @include corner-type-style($-corner-color, $-corner-primary-bg);
@@ -23,6 +26,11 @@
23
26
  @include corner-type-style($-corner-primary-color, $-corner-horizontal-primary-bg);
24
27
  }
25
28
  }
29
+ &.is-embedded {
30
+ .oxy-corner__text {
31
+ @include corner-type-style($-corner-primary-color, $-corner-embedded-primary-bg);
32
+ }
33
+ }
26
34
  }
27
35
  @include when(info) {
28
36
  .oxy-corner__text {
@@ -33,6 +41,11 @@
33
41
  @include corner-type-style($-corner-info-color, $-corner-horizontal-info-bg);
34
42
  }
35
43
  }
44
+ &.is-embedded {
45
+ .oxy-corner__text {
46
+ @include corner-type-style($-corner-info-color, $-corner-embedded-info-bg);
47
+ }
48
+ }
36
49
  }
37
50
  @include when(success) {
38
51
  .oxy-corner__text {
@@ -43,6 +56,11 @@
43
56
  @include corner-type-style($-corner-success-color, $-corner-horizontal-success-bg);
44
57
  }
45
58
  }
59
+ &.is-embedded {
60
+ .oxy-corner__text {
61
+ @include corner-type-style($-corner-success-color, $-corner-embedded-success-bg);
62
+ }
63
+ }
46
64
  }
47
65
  @include when(warning) {
48
66
  .oxy-corner__text {
@@ -53,6 +71,11 @@
53
71
  @include corner-type-style($-corner-warning-color, $-corner-horizontal-warning-bg);
54
72
  }
55
73
  }
74
+ &.is-embedded {
75
+ .oxy-corner__text {
76
+ @include corner-type-style($-corner-warning-color, $-corner-embedded-warning-bg);
77
+ }
78
+ }
56
79
  }
57
80
  @include when(danger) {
58
81
  .oxy-corner__text {
@@ -63,12 +86,21 @@
63
86
  @include corner-type-style($-corner-danger-color, $-corner-horizontal-danger-bg);
64
87
  }
65
88
  }
89
+ &.is-embedded {
90
+ .oxy-corner__text {
91
+ @include corner-type-style($-corner-danger-color, $-corner-embedded-danger-bg);
92
+ }
93
+ }
66
94
  }
67
95
  &:not(.is-horizontal) {
68
96
  &.is-top-left{
69
97
  top: 0;
70
98
  left: 0;
71
99
  right: auto;
100
+ &.is-round {
101
+ border-top-right-radius: 0;
102
+ border-top-left-radius: $-corner-radius;
103
+ }
72
104
  .oxy-corner__text {
73
105
  transform: rotate(-45deg);
74
106
  top: 10px;
@@ -79,6 +111,10 @@
79
111
  bottom: 0;
80
112
  left: 0;
81
113
  top: auto;
114
+ &.is-round {
115
+ border-top-right-radius: 0;
116
+ border-bottom-left-radius: $-corner-radius;
117
+ }
82
118
  .oxy-corner__text {
83
119
  transform: rotate(-135deg);
84
120
  bottom: 10px;
@@ -94,6 +130,10 @@
94
130
  bottom: 0;
95
131
  right: 0;
96
132
  top: auto;
133
+ &.is-round {
134
+ border-top-right-radius: 0;
135
+ border-bottom-right-radius: $-corner-radius;
136
+ }
97
137
  .oxy-corner__text {
98
138
  transform: rotate(135deg);
99
139
  bottom: 10px;
@@ -105,6 +145,62 @@
105
145
  }
106
146
  }
107
147
  }
148
+ &.is-embedded {
149
+ &.is-top-left{
150
+ &::after {
151
+ left: auto;
152
+ right: -6px;
153
+ bottom: 0;
154
+ transform: skewX(-30deg);
155
+ }
156
+ .oxy-corner__text {
157
+ transform: none;
158
+ top: 0;
159
+ left: 0;
160
+ border-bottom-left-radius: 0;
161
+ border-bottom-right-radius: 32px;
162
+ padding-left: 0;
163
+ padding-right: 12px;
164
+ }
165
+ }
166
+ &.is-bottom-left{
167
+ &::after {
168
+ left: auto;
169
+ right: -6px;
170
+ bottom: 0;
171
+ transform: skewX(30deg);
172
+ }
173
+ .oxy-corner__text {
174
+ transform: none;
175
+ bottom: 0;
176
+ left: 0;
177
+ border-bottom-left-radius: 0;
178
+ border-top-right-radius: 32px;
179
+ padding-left: 0;
180
+ padding-right: 12px;
181
+ > span{
182
+ transform: none;
183
+ }
184
+ }
185
+ }
186
+ &.is-bottom-right{
187
+ &::after {
188
+ left: -6px;
189
+ bottom: 0;
190
+ transform: skewX(-30deg);
191
+ }
192
+ .oxy-corner__text {
193
+ transform: none;
194
+ bottom: 0;
195
+ right: 0;
196
+ border-bottom-left-radius: 0;
197
+ border-top-left-radius: 32px;
198
+ > span{
199
+ transform: none;
200
+ }
201
+ }
202
+ }
203
+ }
108
204
  .oxy-corner__text {
109
205
  width: 106px;
110
206
  height: 32px;
@@ -134,5 +230,29 @@
134
230
  text-align: right;
135
231
  }
136
232
  }
233
+ &.is-embedded {
234
+ width: 106px;
235
+ height: 32px;
236
+ &::after {
237
+ content: '';
238
+ position: absolute;
239
+ left: -6px;
240
+ bottom: 0;
241
+ width: 16px;
242
+ height: 32px;
243
+ background-color: #ffffff;
244
+ transform: skewX(30deg);
245
+ }
246
+ .oxy-corner__text {
247
+ right: 0;
248
+ top: 0;
249
+ transform: none;
250
+ padding-left: 12px;
251
+ box-sizing: border-box;
252
+ font-size: $-corner-embedded-font-size;
253
+ font-weight: $-corner-embedded-font-weight;
254
+ border-bottom-left-radius: 32px;
255
+ }
256
+ }
137
257
  }
138
- }
258
+ }
@@ -30,7 +30,7 @@ const props = defineProps(cornerProps)
30
30
  const cornerClass = ref<string>('')
31
31
 
32
32
  watch(
33
- [() => () => props.position, () => props.mode],
33
+ [() => () => props.position, () => props.mode, () => props.round],
34
34
  () => {
35
35
  computeCornerClass()
36
36
  },
@@ -53,11 +53,12 @@ const textClass = computed(() => {
53
53
  })
54
54
 
55
55
  function computeCornerClass() {
56
- const { type, position, mode } = props
56
+ const { type, position, mode, round } = props
57
57
  let cornerClassList: string[] = []
58
58
  type && cornerClassList.push(`is-${type}`)
59
59
  position && cornerClassList.push(`is-${position}`)
60
60
  mode && cornerClassList.push(`is-${mode}`)
61
+ round && cornerClassList.push('is-round')
61
62
  cornerClass.value = cornerClassList.join(' ')
62
63
  }
63
64
  </script>
@@ -3,7 +3,7 @@ import { baseProps, makeBooleanProp, makeStringProp } from '../common/props'
3
3
 
4
4
  export type CornerType = 'primary' | 'info' | 'success' | 'warning' | 'danger'
5
5
  export type CornerPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
6
- export type CornerMode = '' | 'horizontal'
6
+ export type CornerMode = '' | 'horizontal' | 'embedded'
7
7
 
8
8
  export const cornerProps = {
9
9
  ...baseProps,
@@ -24,10 +24,17 @@ export const cornerProps = {
24
24
  */
25
25
  position: makeStringProp<CornerPosition>('top-right'),
26
26
 
27
+ /**
28
+ * 圆角类型
29
+ * 类型:boolean
30
+ * 默认值:false
31
+ */
32
+ round: makeBooleanProp(false),
33
+
27
34
  /**
28
35
  * 角标模式
29
36
  * 类型:string
30
- * 可选值:'horizontal'
37
+ * 可选值:'horizontal' / 'embedded'
31
38
  * 默认值:''
32
39
  */
33
40
  mode: makeStringProp<CornerMode>(''),
@@ -1,4 +1,5 @@
1
1
  @import './../common/abstracts/_mixin.scss';
2
2
  @import './../common/abstracts/variable.scss';
3
- @include b(list) {
4
- }
3
+ @import './../oxy-virtual-scroll/index.scss';
4
+
5
+ @include b(list) {}
@@ -1,38 +1,61 @@
1
1
  <template>
2
- <view :class="['oxy-list', customClass]" :style="customStyle">
3
- <oxy-virtual-scroll
4
- ref="virtualScrollRef"
5
- :is-virtual="virtual"
6
- :data="data"
7
- :height="height"
8
- :item-height="itemHeight"
9
- :id-key="idKey"
10
- :show-back-to-top="showBackToTop"
11
- :back-to-top-threshold="backToTopThreshold"
2
+ <view :class="['oxy-list', 'oxy-virtual-scroll', customClass]" :style="customStyle">
3
+ <!-- 滚动内容区域 -->
4
+ <scroll-view
5
+ v-if="data.length"
6
+ :style="{ height: height }"
7
+ class="oxy-virtual-scroll__view"
8
+ :scroll-y="true"
9
+ :scroll-x="scrollX"
10
+ :upper-threshold="upperThreshold"
11
+ :lower-threshold="lowerThreshold"
12
+ :scroll-top="scrollTop"
13
+ :scroll-left="scrollLeft"
14
+ :scroll-with-animation="scrollWithAnimation"
15
+ :enable-back-to-top="enableBackToTop"
16
+ :show-scrollbar="showScrollbar"
17
+ :refresher-enabled="refresherEnabled"
18
+ :refresher-threshold="refresherThreshold"
19
+ :refresher-default-style="refresherDefaultStyle"
20
+ :refresher-background="refresherBackground"
12
21
  :refresher-triggered="triggered"
13
- v-bind="{ ...defaultscrollConfig, ...scrollConfig }"
14
- @scroll-to-upper="onScrollToUpper"
15
- @scroll-to-lower="onScrollToLower"
16
- @scroll="onScroll"
22
+ :enable-flex="enableFlex"
23
+ :scroll-anchoring="scrollAnchoring"
24
+ @scroll="handleScroll"
25
+ @scrolltoupper="onScrollToUpper"
26
+ @scrolltolower="onScrollToLower"
17
27
  @refresherrefresh="onRefresh"
18
28
  @refresherrestore="onRestore"
19
29
  @refresherabort="onAbort"
20
30
  >
21
- <template #item="{ item }">
22
- <slot name="item" :item="item"></slot>
23
- </template>
24
- <template #bottom>
25
- <oxy-loadmore
26
- v-if="loadmoreState"
27
- :state="loadmoreState"
28
- :loading-text="loadingText"
29
- :finished-text="finishedText"
30
- :error-text="errorText"
31
- :loading-props="loadingProps"
32
- @reload="onReload"
33
- />
34
- </template>
35
- </oxy-virtual-scroll>
31
+ <view class="oxy-virtual-scroll__container" :style="{ height: totalHeight + 'px' }">
32
+ <view class="oxy-virtual-scroll__items" :style="{ transform: `translateY(${virtualOffsetY}px)` }">
33
+ <view v-for="(item, index) in virtualData" :key="index">
34
+ <slot name="item" :item="item" :index="startIndex + index"></slot>
35
+ </view>
36
+ <slot name="bottom">
37
+ <oxy-loadmore
38
+ v-if="loadmoreState"
39
+ :state="loadmoreState"
40
+ :loading-text="loadingText"
41
+ :finished-text="finishedText"
42
+ :error-text="errorText"
43
+ :loading-props="loadingProps"
44
+ @reload="onReload"
45
+ />
46
+ </slot>
47
+ </view>
48
+ </view>
49
+ </scroll-view>
50
+
51
+ <view v-else>
52
+ <oxy-status-tip image="content" :tip="emptyText" />
53
+ </view>
54
+
55
+ <!-- 回到顶部按钮 -->
56
+ <view v-if="showBackToTop && showBackTopBtn" class="oxy-virtual-scroll__back-top" @click="scrollToTop">
57
+ <oxy-icon name="backtop" color="#fff" size="20px"></oxy-icon>
58
+ </view>
36
59
  </view>
37
60
  </template>
38
61
 
@@ -48,7 +71,7 @@ export default {
48
71
  </script>
49
72
 
50
73
  <script lang="ts" setup>
51
- import { computed, ref } from 'vue'
74
+ import { computed, toRefs } from 'vue'
52
75
  import { type ListExpose, listProps } from './types'
53
76
  import type {
54
77
  ScrollViewOnRefresherabortEvent,
@@ -56,18 +79,70 @@ import type {
56
79
  ScrollViewOnRefresherrestoreEvent,
57
80
  ScrollViewOnScrollEvent
58
81
  } from '@uni-helper/uni-app-types/index'
59
- import type { VirtualScrollInstance } from '../oxy-virtual-scroll/types'
82
+ import { useVirtualScroll } from '../composables/useVirtualScroll'
60
83
 
61
84
  const props = defineProps(listProps)
62
85
 
63
86
  const emit = defineEmits(['scroll-to-lower', 'reload', 'scroll-to-upper', 'scroll', 'refresh', 'restore', 'abort'])
64
- const virtualScrollRef = ref<VirtualScrollInstance | null>(null)
65
87
 
66
88
  const defaultscrollConfig = {
67
- refresherEnabled: true,
89
+ refresherEnabled: false,
68
90
  refresherThreshold: 60,
69
91
  scrollWithAnimation: false
70
- }
92
+ } as const
93
+
94
+ // 解构props用于组合式函数
95
+ const {
96
+ data,
97
+ virtual,
98
+ height,
99
+ itemHeight,
100
+ idKey,
101
+ showBackToTop,
102
+ backToTopThreshold,
103
+ scrollY,
104
+ scrollX,
105
+ upperThreshold,
106
+ lowerThreshold,
107
+ scrollLeft,
108
+ scrollWithAnimation,
109
+ enableBackToTop,
110
+ showScrollbar,
111
+ refresherEnabled,
112
+ refresherThreshold,
113
+ refresherDefaultStyle,
114
+ refresherBackground,
115
+ triggered,
116
+ enableFlex,
117
+ scrollAnchoring
118
+ } = toRefs(props)
119
+
120
+ // 使用虚拟滚动组合式函数
121
+ const {
122
+ scrollTop,
123
+ showBackTopBtn,
124
+ virtualData,
125
+ startIndex,
126
+ virtualOffsetY,
127
+ totalHeight,
128
+ displayData,
129
+ initScrollData,
130
+ initScrollEngine,
131
+ updateVisibleData,
132
+ scrollToTop: virtualScrollToTop,
133
+ scrollToBottom: virtualScrollToBottom,
134
+ scrollToPosition: virtualScrollToPosition,
135
+ scrollToElement: virtualScrollToElement,
136
+ scrollToElementById: virtualScrollToElementById,
137
+ onScroll: handleVirtualScroll
138
+ } = useVirtualScroll({
139
+ data,
140
+ virtual,
141
+ height,
142
+ itemHeight,
143
+ idKey,
144
+ backToTopThreshold
145
+ })
71
146
 
72
147
  const onScrollToLower = async () => {
73
148
  emit('scroll-to-lower')
@@ -78,7 +153,10 @@ const onScrollToUpper = async () => {
78
153
  const onReload = async () => {
79
154
  emit('reload')
80
155
  }
81
- const onScroll = async (event: ScrollViewOnScrollEvent) => {
156
+
157
+ // 滚动事件处理
158
+ const handleScroll = async (event: ScrollViewOnScrollEvent) => {
159
+ handleVirtualScroll(event.detail.scrollTop)
82
160
  emit('scroll', event)
83
161
  }
84
162
 
@@ -96,21 +174,24 @@ const onRestore = (e: ScrollViewOnRefresherrestoreEvent) => {
96
174
  const onAbort = (e: ScrollViewOnRefresherabortEvent) => {
97
175
  emit('abort', e)
98
176
  }
177
+
178
+ // 滚动方法
99
179
  const scrollToTop = () => {
100
- virtualScrollRef.value?.scrollToTop()
180
+ virtualScrollToTop()
101
181
  }
102
182
  const scrollToBottom = () => {
103
- virtualScrollRef.value?.scrollToBottom()
183
+ virtualScrollToBottom()
104
184
  }
105
185
  const scrollToPosition = (position: number | string) => {
106
- virtualScrollRef.value?.scrollToPosition(position)
186
+ virtualScrollToPosition(position)
107
187
  }
108
188
  const scrollToElement = (item: any) => {
109
- virtualScrollRef.value?.scrollToElement(item)
189
+ virtualScrollToElement(item)
110
190
  }
111
191
  const scrollToElementById = (id: string | number) => {
112
- virtualScrollRef.value?.scrollToElementById(id)
192
+ virtualScrollToElementById(id)
113
193
  }
194
+
114
195
  defineExpose<ListExpose>({
115
196
  scrollToTop,
116
197
  scrollToBottom,
@@ -1,5 +1,5 @@
1
1
  import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
2
- import { makeBooleanProp } from '../common/props'
2
+ import { makeBooleanProp, makeNumberProp, makeStringProp } from '../common/props'
3
3
  import { type LoadMoreState } from '../oxy-loadmore/types'
4
4
  import { type LoadingProps } from '../oxy-loading/types'
5
5
  import { virtualScrollProps } from '../oxy-virtual-scroll/types'
@@ -25,19 +25,7 @@ export const listProps = {
25
25
  * 加载中loading组件的属性
26
26
  * 参考loading组件
27
27
  */
28
- loadingProps: Object as PropType<Partial<LoadingProps>>,
29
- triggered: makeBooleanProp(false),
30
- scrollConfig: {
31
- type: Object as PropType<ScrollConfig>,
32
- default: () => ({})
33
- }
34
- }
35
- export type ScrollConfig = {
36
- refresherEnabled: boolean
37
- refresherThreshold: number
38
- refresherBackground: string
39
- animation: boolean
40
- [key: string]: any
28
+ loadingProps: Object as PropType<Partial<LoadingProps>>
41
29
  }
42
30
  export type ListExpose = {
43
31
  scrollToTop: () => void