vxe-pc-ui 4.18.21 → 4.18.23

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.
Files changed (84) hide show
  1. package/dist/all.esm.js +1638 -1048
  2. package/dist/style.css +1 -1
  3. package/dist/style.min.css +1 -1
  4. package/es/components.js +3 -0
  5. package/es/icon/style.css +1 -1
  6. package/es/result/src/result.js +1 -1
  7. package/es/scrollbar/index.js +12 -0
  8. package/es/scrollbar/src/scrollbar.js +520 -0
  9. package/es/scrollbar/src/util.js +54 -0
  10. package/es/scrollbar/style.css +101 -0
  11. package/es/scrollbar/style.min.css +1 -0
  12. package/es/style.css +1 -1
  13. package/es/style.min.css +1 -1
  14. package/es/ui/index.js +10 -1
  15. package/es/ui/src/log.js +1 -1
  16. package/es/upload/style.css +5 -3
  17. package/es/upload/style.min.css +1 -1
  18. package/es/vxe-scrollbar/index.js +3 -0
  19. package/es/vxe-scrollbar/style.css +101 -0
  20. package/es/vxe-scrollbar/style.min.css +1 -0
  21. package/es/vxe-upload/style.css +5 -3
  22. package/es/vxe-upload/style.min.css +1 -1
  23. package/lib/components.js +13 -1
  24. package/lib/components.min.js +1 -1
  25. package/lib/icon/style/style.css +1 -1
  26. package/lib/icon/style/style.min.css +1 -1
  27. package/lib/index.umd.js +697 -6
  28. package/lib/index.umd.min.js +1 -1
  29. package/lib/result/src/result.js +1 -1
  30. package/lib/result/src/result.min.js +1 -1
  31. package/lib/scrollbar/index.js +19 -0
  32. package/lib/scrollbar/index.min.js +1 -0
  33. package/lib/scrollbar/src/scrollbar.js +560 -0
  34. package/lib/scrollbar/src/scrollbar.min.js +1 -0
  35. package/lib/scrollbar/src/util.js +63 -0
  36. package/lib/scrollbar/src/util.min.js +1 -0
  37. package/lib/scrollbar/style/index.js +1 -0
  38. package/lib/scrollbar/style/style.css +101 -0
  39. package/lib/scrollbar/style/style.min.css +1 -0
  40. package/lib/style.css +1 -1
  41. package/lib/style.min.css +1 -1
  42. package/lib/ui/index.js +10 -1
  43. package/lib/ui/index.min.js +1 -1
  44. package/lib/ui/src/log.js +1 -1
  45. package/lib/ui/src/log.min.js +1 -1
  46. package/lib/upload/style/style.css +5 -3
  47. package/lib/upload/style/style.min.css +1 -1
  48. package/lib/vxe-scrollbar/index.js +21 -0
  49. package/lib/vxe-scrollbar/index.min.js +1 -0
  50. package/lib/vxe-scrollbar/style/index.js +1 -0
  51. package/lib/vxe-scrollbar/style/style.css +101 -0
  52. package/lib/vxe-scrollbar/style/style.min.css +1 -0
  53. package/lib/vxe-upload/style/style.css +5 -3
  54. package/lib/vxe-upload/style/style.min.css +1 -1
  55. package/package.json +2 -2
  56. package/packages/components.ts +3 -0
  57. package/packages/result/src/result.ts +1 -1
  58. package/packages/scrollbar/index.ts +16 -0
  59. package/packages/scrollbar/src/scrollbar.ts +564 -0
  60. package/packages/scrollbar/src/util.ts +57 -0
  61. package/packages/ui/index.ts +9 -0
  62. package/styles/all.scss +1 -0
  63. package/styles/components/scrollbar.scss +114 -0
  64. package/styles/components/upload.scss +5 -3
  65. package/styles/theme/base.scss +5 -0
  66. package/styles/theme/dark.scss +5 -0
  67. package/styles/theme/light.scss +5 -0
  68. package/styles/variable.scss +5 -0
  69. package/types/all.d.ts +3 -0
  70. package/types/components/gantt.d.ts +3 -3
  71. package/types/components/scrollbar.d.ts +216 -0
  72. package/types/ui/global-config.d.ts +2 -0
  73. /package/es/icon/{iconfont.1790757619500.ttf → iconfont.1791517860186.ttf} +0 -0
  74. /package/es/icon/{iconfont.1790757619500.woff → iconfont.1791517860186.woff} +0 -0
  75. /package/es/icon/{iconfont.1790757619500.woff2 → iconfont.1791517860186.woff2} +0 -0
  76. /package/es/{iconfont.1790757619500.ttf → iconfont.1791517860186.ttf} +0 -0
  77. /package/es/{iconfont.1790757619500.woff → iconfont.1791517860186.woff} +0 -0
  78. /package/es/{iconfont.1790757619500.woff2 → iconfont.1791517860186.woff2} +0 -0
  79. /package/lib/icon/style/{iconfont.1790757619500.ttf → iconfont.1791517860186.ttf} +0 -0
  80. /package/lib/icon/style/{iconfont.1790757619500.woff → iconfont.1791517860186.woff} +0 -0
  81. /package/lib/icon/style/{iconfont.1790757619500.woff2 → iconfont.1791517860186.woff2} +0 -0
  82. /package/lib/{iconfont.1790757619500.ttf → iconfont.1791517860186.ttf} +0 -0
  83. /package/lib/{iconfont.1790757619500.woff → iconfont.1791517860186.woff} +0 -0
  84. /package/lib/{iconfont.1790757619500.woff2 → iconfont.1791517860186.woff2} +0 -0
@@ -0,0 +1,564 @@
1
+ import { ref, h, reactive, computed, PropType, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'
2
+ import { defineVxeComponent } from '../../ui/src/comp'
3
+ import XEUtils from 'xe-utils'
4
+ import { VxeUI } from '../../ui'
5
+ import { toCssUnit } from '../../ui/src/dom'
6
+ import { getThumbOffsetSize, getThumbSize, getScrollFromClick, getScrollFromDrag } from './util'
7
+ import VxeLoadingComponent from '../../loading'
8
+
9
+ import type { ScrollbarReactData, ScrollbarInternalData, VxeScrollbarEmits, ScrollbarMethods, ScrollbarPrivateMethods, VxeScrollbarPropTypes, ValueOf, ScrollbarPrivateRef, VxeScrollbarPrivateComputed, VxeScrollbarConstructor, VxeScrollbarPrivateMethods, VxeComponentStyleType } from '../../../types'
10
+
11
+ const { getConfig, createEvent, domUtils, globalResize, renderEmptyElement } = VxeUI
12
+
13
+ function createReactData (): ScrollbarReactData {
14
+ return {
15
+ yThumbHeight: 0,
16
+ xThumbWidth: 0
17
+ }
18
+ }
19
+
20
+ function createInternalData (): ScrollbarInternalData {
21
+ return {
22
+ // resizeObserver: undefined,
23
+ // isThumbDrag: false,
24
+ thumbDragOffset: 0,
25
+ yThumbTop: 0,
26
+ xThumbLeft: 0,
27
+ lastScrollTop: 0,
28
+ lastScrollLeft: 0
29
+ }
30
+ }
31
+
32
+ export default defineVxeComponent({
33
+ name: 'VxeScrollbar',
34
+ props: {
35
+ width: [String, Number] as PropType<VxeScrollbarPropTypes.Width>,
36
+ height: [String, Number] as PropType<VxeScrollbarPropTypes.Height>,
37
+ minWidth: [String, Number] as PropType<VxeScrollbarPropTypes.MinWidth>,
38
+ minHeight: [String, Number] as PropType<VxeScrollbarPropTypes.MinHeight>,
39
+ maxWidth: [String, Number] as PropType<VxeScrollbarPropTypes.MaxWidth>,
40
+ maxHeight: [String, Number] as PropType<VxeScrollbarPropTypes.MaxHeight>,
41
+ loading: Boolean as PropType<VxeScrollbarPropTypes.Loading>,
42
+ native: {
43
+ type: Boolean as PropType<VxeScrollbarPropTypes.Native>,
44
+ default: () => getConfig().scrollbar.native
45
+ },
46
+ xConfig: Object as PropType<VxeScrollbarPropTypes.XConfig>,
47
+ yConfig: Object as PropType<VxeScrollbarPropTypes.YConfig>,
48
+ className: String as PropType<VxeScrollbarPropTypes.ClassName>,
49
+ viewClassName: String as PropType<VxeScrollbarPropTypes.ViewClassName>,
50
+ autoResize: {
51
+ type: Boolean as PropType<VxeScrollbarPropTypes.AutoResize>,
52
+ default: () => getConfig().scrollbar.autoResize
53
+ },
54
+ syncResize: [Boolean, String, Number] as PropType<VxeScrollbarPropTypes.SyncResize>
55
+ },
56
+ emits: [
57
+ 'scroll',
58
+ 'scroll-boundary'
59
+ ] as VxeScrollbarEmits,
60
+ setup (props, context) {
61
+ const { emit, slots } = context
62
+
63
+ const xID = XEUtils.uniqueId()
64
+
65
+ const refElem = ref<HTMLDivElement>()
66
+ const refViewElem = ref<HTMLDivElement>()
67
+ const refViewInnerElem = ref<HTMLDivElement>()
68
+ const refTrackXElem = ref<HTMLDivElement>()
69
+ const refTrackYElem = ref<HTMLDivElement>()
70
+ const refThumbXElem = ref<HTMLDivElement>()
71
+ const refThumbYElem = ref<HTMLDivElement>()
72
+
73
+ const reactData = reactive(createReactData())
74
+
75
+ const internalData = createInternalData()
76
+
77
+ const computeWrapperStyle = computed(() => {
78
+ const { width, height, minWidth, minHeight, maxWidth, maxHeight } = props
79
+ const xOpts = computeXOpts.value
80
+ const yOpts = computeYOpts.value
81
+ const stys: VxeComponentStyleType = {}
82
+ if (width) {
83
+ stys.width = toCssUnit(width)
84
+ }
85
+ if (height) {
86
+ stys.height = toCssUnit(height)
87
+ }
88
+ if (minWidth) {
89
+ stys.minWidth = toCssUnit(minWidth)
90
+ }
91
+ if (minHeight) {
92
+ stys.minHeight = toCssUnit(minHeight)
93
+ }
94
+ if (maxWidth) {
95
+ stys.maxWidth = toCssUnit(maxWidth)
96
+ }
97
+ if (maxHeight) {
98
+ stys.maxHeight = toCssUnit(maxHeight)
99
+ }
100
+ if (yOpts.width) {
101
+ stys['--vxe-ui-scrollbar-y-width'] = toCssUnit(yOpts.width)
102
+ }
103
+ if (xOpts.height) {
104
+ stys['--vxe-ui-scrollbar-x-height'] = toCssUnit(xOpts.height)
105
+ }
106
+ return stys
107
+ })
108
+
109
+ const computeWrapperClss = computed(() => {
110
+ const { native, className } = props
111
+ const xOpts = computeXOpts.value
112
+ const yOpts = computeYOpts.value
113
+ return domUtils.buildClass([
114
+ 'vxe-scrollbar',
115
+ `ov-x--${xOpts.visible || 'visible'}`,
116
+ `ov-y--${yOpts.visible || 'visible'}`,
117
+ native ? 'is--native' : 'is--virtual',
118
+ className
119
+ ], {
120
+ 'ov-x--auto-hide': xOpts.autoHide,
121
+ 'ov-y--auto-hide': yOpts.autoHide
122
+ })
123
+ })
124
+
125
+ const computeViewClss = computed(() => {
126
+ const { viewClassName } = props
127
+ return domUtils.buildClass([
128
+ 'vxe-scrollbar--view',
129
+ viewClassName
130
+ ])
131
+ })
132
+
133
+ const computeXOpts = computed(() => {
134
+ return Object.assign({}, getConfig().scrollbar.xConfig, props.xConfig)
135
+ })
136
+
137
+ const computeYOpts = computed(() => {
138
+ return Object.assign({}, getConfig().scrollbar.yConfig, props.yConfig)
139
+ })
140
+
141
+ const refMaps: ScrollbarPrivateRef = {
142
+ refElem
143
+ }
144
+
145
+ const computeMaps: VxeScrollbarPrivateComputed = {
146
+ }
147
+
148
+ const $xeScrollbar = {
149
+ xID,
150
+ props,
151
+ context,
152
+ reactData,
153
+ internalData,
154
+
155
+ getRefMaps: () => refMaps,
156
+ getComputeMaps: () => computeMaps
157
+ } as unknown as VxeScrollbarConstructor & VxeScrollbarPrivateMethods
158
+
159
+ const dispatchEvent = (type: ValueOf<VxeScrollbarEmits>, params: Record<string, any>, evnt: Event | null) => {
160
+ emit(type, createEvent(evnt, { $scrollbar: $xeScrollbar }, params))
161
+ }
162
+
163
+ const scrollbarMethods: ScrollbarMethods = {
164
+ dispatchEvent,
165
+ scrollTo (left: ScrollToOptions | number, top?: number) {
166
+ const viewEl = refViewElem.value
167
+ if (viewEl) {
168
+ if (XEUtils.isNumber(left)) {
169
+ viewEl.scrollTo(left, top || 0)
170
+ } else {
171
+ viewEl.scrollTo(left)
172
+ }
173
+ }
174
+ },
175
+ scrollIntoView () {
176
+ const viewEl = refViewElem.value
177
+ if (viewEl) {
178
+ viewEl.scrollIntoView()
179
+ }
180
+ },
181
+ recalculate () {
182
+ updateThumbSize()
183
+ updateThumbOffset()
184
+ return nextTick()
185
+ }
186
+ }
187
+
188
+ const updateThumbSize = () => {
189
+ const viewEl = refViewElem.value
190
+ if (!viewEl) {
191
+ return
192
+ }
193
+ const trackXEl = refTrackXElem.value
194
+ const xThumbWidth = trackXEl ? getThumbSize(viewEl.clientWidth, viewEl.scrollWidth, trackXEl.clientWidth) : 0
195
+ const thumbXElem = refThumbXElem.value
196
+ if (thumbXElem) {
197
+ thumbXElem.style.width = xThumbWidth + 'px'
198
+ }
199
+ reactData.xThumbWidth = xThumbWidth
200
+
201
+ const trackYEl = refTrackYElem.value
202
+ const yThumbHeight = trackYEl ? getThumbSize(viewEl.clientHeight, viewEl.scrollHeight, trackYEl.clientHeight) : 0
203
+ const thumbYElem = refThumbYElem.value
204
+ if (thumbYElem) {
205
+ thumbYElem.style.height = yThumbHeight + 'px'
206
+ }
207
+ reactData.yThumbHeight = yThumbHeight
208
+ }
209
+
210
+ const updateThumbOffset = () => {
211
+ const viewEl = refViewElem.value
212
+ if (!viewEl) {
213
+ return
214
+ }
215
+ const { xThumbWidth, yThumbHeight } = reactData
216
+ const trackXEl = refTrackXElem.value
217
+ const thumbXElem = refThumbXElem.value
218
+ const xThumbLeft = trackXEl && xThumbWidth ? getThumbOffsetSize(viewEl.scrollLeft, viewEl.clientWidth, viewEl.scrollWidth, trackXEl.clientWidth, xThumbWidth) : 0
219
+ internalData.xThumbLeft = xThumbLeft
220
+ if (thumbXElem && xThumbWidth) {
221
+ thumbXElem.style.width = xThumbWidth + 'px'
222
+ thumbXElem.style.transform = `translateX(${xThumbLeft}px)`
223
+ }
224
+
225
+ const trackYEl = refTrackYElem.value
226
+ const thumbYElem = refThumbYElem.value
227
+ const yThumbTop = trackYEl && yThumbHeight ? getThumbOffsetSize(viewEl.scrollTop, viewEl.clientHeight, viewEl.scrollHeight, trackYEl.clientHeight, yThumbHeight) : 0
228
+ internalData.yThumbTop = yThumbTop
229
+ if (thumbYElem && yThumbHeight) {
230
+ thumbYElem.style.height = yThumbHeight + 'px'
231
+ thumbYElem.style.transform = `translateY(${yThumbTop}px)`
232
+ }
233
+ }
234
+
235
+ const scrollEvent = (evnt: Event) => {
236
+ const { xThumbWidth, yThumbHeight } = reactData
237
+ const { lastScrollTop, lastScrollLeft } = internalData
238
+ const xOpts = computeXOpts.value
239
+ const yOpts = computeYOpts.value
240
+ const viewEl = evnt.currentTarget as HTMLDivElement
241
+ const { scrollTop, scrollLeft, clientWidth, clientHeight, scrollHeight, scrollWidth } = viewEl
242
+ let direction = ''
243
+ let isTopBoundary = false
244
+ let isBottomBoundary = false
245
+ let isLeftBoundary = false
246
+ let isRightBoundary = false
247
+ if (lastScrollTop !== scrollTop) {
248
+ const yThreshold = XEUtils.toNumber(yOpts.threshold) || 1
249
+ if (lastScrollTop < scrollTop) {
250
+ direction = 'bottom'
251
+ if (yThumbHeight > 0 && scrollTop + clientHeight >= scrollHeight - yThreshold) {
252
+ isBottomBoundary = true
253
+ }
254
+ } else {
255
+ direction = 'top'
256
+ if (yThumbHeight > 0 && scrollTop <= yThreshold) {
257
+ isTopBoundary = true
258
+ }
259
+ }
260
+ }
261
+ if (lastScrollLeft !== scrollLeft) {
262
+ const xThreshold = XEUtils.toNumber(xOpts.threshold) || 1
263
+ if (lastScrollLeft < scrollLeft) {
264
+ direction = 'right'
265
+ if (xThumbWidth > 0 && scrollLeft + clientWidth >= scrollWidth - xThreshold) {
266
+ isRightBoundary = true
267
+ }
268
+ } else {
269
+ direction = 'left'
270
+ if (xThumbWidth > 0 && scrollLeft <= xThreshold) {
271
+ isLeftBoundary = true
272
+ }
273
+ }
274
+ }
275
+ updateThumbOffset()
276
+ internalData.lastScrollTop = scrollTop
277
+ internalData.lastScrollLeft = scrollLeft
278
+ if (isBottomBoundary || isTopBoundary || isRightBoundary || isLeftBoundary) {
279
+ dispatchEvent('scroll-boundary', {
280
+ direction: direction,
281
+ isTop: isTopBoundary,
282
+ isBottom: isBottomBoundary,
283
+ isLeft: isLeftBoundary,
284
+ isRight: isRightBoundary,
285
+ scrollTop: scrollTop,
286
+ scrollLeft: scrollLeft,
287
+ clientWidth: clientWidth,
288
+ clientHeight: clientHeight,
289
+ scrollHeight: scrollHeight,
290
+ scrollWidth: scrollWidth
291
+ }, evnt)
292
+ }
293
+ dispatchEvent('scroll', {
294
+ direction: direction,
295
+ isTop: yThumbHeight > 0 && scrollTop <= 0,
296
+ isBottom: yThumbHeight > 0 && scrollTop + clientHeight >= scrollHeight,
297
+ isLeft: xThumbWidth > 0 && scrollLeft <= 0,
298
+ isRight: xThumbWidth > 0 && scrollLeft + clientWidth >= scrollWidth,
299
+ scrollTop: scrollTop,
300
+ scrollLeft: scrollLeft,
301
+ clientWidth: clientWidth,
302
+ clientHeight: clientHeight,
303
+ scrollHeight: scrollHeight,
304
+ scrollWidth: scrollWidth
305
+ }, evnt)
306
+ }
307
+
308
+ const clickTrackXEvent = (evnt: MouseEvent) => {
309
+ const trackEl = evnt.currentTarget as HTMLDivElement
310
+ if (trackEl !== evnt.target) {
311
+ return
312
+ }
313
+ const viewEl = refViewElem.value
314
+ if (!viewEl) {
315
+ return
316
+ }
317
+ const { xThumbWidth } = reactData
318
+ const trackRect = trackEl.getBoundingClientRect()
319
+ viewEl.scrollTo({
320
+ left: getScrollFromClick(evnt.clientX - trackRect.left, viewEl.clientWidth, viewEl.scrollWidth, trackEl.clientWidth, xThumbWidth),
321
+ behavior: 'auto'
322
+ })
323
+ }
324
+
325
+ const clickTrackYEvent = (evnt: MouseEvent) => {
326
+ const trackEl = evnt.currentTarget as HTMLDivElement
327
+ if (trackEl !== evnt.target) {
328
+ return
329
+ }
330
+ const viewEl = refViewElem.value
331
+ if (!viewEl) {
332
+ return
333
+ }
334
+ const { yThumbHeight } = reactData
335
+ const trackRect = trackEl.getBoundingClientRect()
336
+ viewEl.scrollTo({
337
+ top: getScrollFromClick(evnt.clientY - trackRect.top, viewEl.clientHeight, viewEl.scrollHeight, trackEl.clientHeight, yThumbHeight),
338
+ behavior: 'auto'
339
+ })
340
+ }
341
+
342
+ const pointerdownThumbXEvent = (evnt: PointerEvent) => {
343
+ const thumbEl = evnt.currentTarget as HTMLDivElement
344
+ internalData.isThumbDrag = true
345
+ thumbEl.setPointerCapture(evnt.pointerId)
346
+
347
+ const viewEl = refViewElem.value
348
+ if (!viewEl) {
349
+ return
350
+ }
351
+ const { xThumbWidth } = reactData
352
+ const trackEl = thumbEl.parentElement as HTMLDivElement
353
+ const trackRect = trackEl.getBoundingClientRect()
354
+ const pointerPosition = evnt.clientX - trackRect.left
355
+ // 记录 thumb 的偏移
356
+ const thumbOffset = getThumbOffsetSize(viewEl.scrollLeft, viewEl.clientWidth, viewEl.scrollWidth, trackEl.clientWidth, xThumbWidth)
357
+ internalData.thumbDragOffset = pointerPosition - thumbOffset
358
+ }
359
+
360
+ const pointermoveThumbXEvent = (evnt: PointerEvent) => {
361
+ const thumbEl = evnt.currentTarget as HTMLDivElement
362
+ if (!thumbEl.hasPointerCapture(evnt.pointerId)) {
363
+ return
364
+ }
365
+ const { isThumbDrag, thumbDragOffset } = internalData
366
+ if (isThumbDrag) {
367
+ const viewEl = refViewElem.value
368
+ if (!viewEl) {
369
+ return
370
+ }
371
+ const { xThumbWidth } = reactData
372
+ const thumbEl = evnt.currentTarget as HTMLDivElement
373
+ const trackEl = thumbEl.parentElement as HTMLDivElement
374
+ const trackRect = trackEl.getBoundingClientRect()
375
+ // 更新偏移
376
+ viewEl.scrollLeft = getScrollFromDrag(evnt.clientX - trackRect.left, thumbDragOffset, viewEl.clientWidth, viewEl.scrollWidth, trackEl.clientWidth, xThumbWidth)
377
+ }
378
+ }
379
+
380
+ const cleatPointerThumbEvent = (evnt: PointerEvent) => {
381
+ const thumbEl = evnt.currentTarget as HTMLDivElement
382
+ thumbEl.releasePointerCapture(evnt.pointerId)
383
+ internalData.isThumbDrag = false
384
+ }
385
+
386
+ const pointerdownThumbYEvent = (evnt: PointerEvent) => {
387
+ const thumbEl = evnt.currentTarget as HTMLDivElement
388
+ internalData.isThumbDrag = true
389
+ thumbEl.setPointerCapture(evnt.pointerId)
390
+
391
+ const viewEl = refViewElem.value
392
+ if (!viewEl) {
393
+ return
394
+ }
395
+ const { yThumbHeight } = reactData
396
+ const trackEl = thumbEl.parentElement as HTMLDivElement
397
+ const trackRect = trackEl.getBoundingClientRect()
398
+ const pointerPosition = evnt.clientY - trackRect.top
399
+ // 记录 thumb 的偏移
400
+ const thumbOffset = getThumbOffsetSize(viewEl.scrollTop, viewEl.clientHeight, viewEl.scrollHeight, trackEl.clientHeight, yThumbHeight)
401
+ internalData.thumbDragOffset = pointerPosition - thumbOffset
402
+ }
403
+
404
+ const pointermoveThumbYEvent = (evnt: PointerEvent) => {
405
+ const thumbEl = evnt.currentTarget as HTMLDivElement
406
+ if (!thumbEl.hasPointerCapture(evnt.pointerId)) {
407
+ return
408
+ }
409
+ const { isThumbDrag, thumbDragOffset } = internalData
410
+ if (isThumbDrag) {
411
+ const viewEl = refViewElem.value
412
+ if (!viewEl) {
413
+ return
414
+ }
415
+ const { yThumbHeight } = reactData
416
+ const thumbEl = evnt.currentTarget as HTMLDivElement
417
+ const trackEl = thumbEl.parentElement as HTMLDivElement
418
+ const trackRect = trackEl.getBoundingClientRect()
419
+ // 更新偏移
420
+ viewEl.scrollTop = getScrollFromDrag(evnt.clientY - trackRect.top, thumbDragOffset, viewEl.clientHeight, viewEl.scrollHeight, trackEl.clientHeight, yThumbHeight)
421
+ }
422
+ }
423
+
424
+ const scrollbarPrivateMethods: ScrollbarPrivateMethods = {
425
+ }
426
+
427
+ Object.assign($xeScrollbar, scrollbarMethods, scrollbarPrivateMethods)
428
+
429
+ const renderVN = () => {
430
+ const { native, loading, autoResize } = props
431
+ const wrapperStyle = computeWrapperStyle.value
432
+ const wrapperClss = computeWrapperClss.value
433
+ const viewClss = computeViewClss.value
434
+ const xOpts = computeXOpts.value
435
+ const yOpts = computeYOpts.value
436
+ const defaultSlot = slots.default
437
+ return h('div', {
438
+ ref: refElem,
439
+ class: wrapperClss,
440
+ style: wrapperStyle
441
+ }, [
442
+ h('div', {
443
+ ref: refViewElem,
444
+ class: viewClss,
445
+ onScroll: scrollEvent
446
+ }, autoResize
447
+ ? [
448
+ h('div', {
449
+ key: 'vi',
450
+ ref: refViewInnerElem,
451
+ class: 'vxe-scrollbar--view-inner'
452
+ }, defaultSlot ? defaultSlot({}) : [])
453
+ ]
454
+ : defaultSlot ? defaultSlot({}) : []),
455
+ native || xOpts.visible === 'hidden'
456
+ ? renderEmptyElement($xeScrollbar)
457
+ : h('div', {
458
+ ref: refTrackXElem,
459
+ class: 'vxe-scrollbar--track-x',
460
+ onClick: clickTrackXEvent
461
+ }, [
462
+ h('div', {
463
+ ref: refThumbXElem,
464
+ class: 'vxe-scrollbar--thumb-x',
465
+ onPointerdown: pointerdownThumbXEvent,
466
+ onPointermove: pointermoveThumbXEvent,
467
+ onPointerup: cleatPointerThumbEvent,
468
+ onPointercancel: cleatPointerThumbEvent,
469
+ onLostpointercapture: cleatPointerThumbEvent
470
+ })
471
+ ]),
472
+ native || yOpts.visible === 'hidden'
473
+ ? renderEmptyElement($xeScrollbar)
474
+ : h('div', {
475
+ ref: refTrackYElem,
476
+ class: 'vxe-scrollbar--track-y',
477
+ onClick: clickTrackYEvent
478
+ }, [
479
+ h('div', {
480
+ ref: refThumbYElem,
481
+ class: 'vxe-scrollbar--thumb-y',
482
+ onPointerdown: pointerdownThumbYEvent,
483
+ onPointermove: pointermoveThumbYEvent,
484
+ onPointerup: cleatPointerThumbEvent,
485
+ onPointercancel: cleatPointerThumbEvent,
486
+ onLostpointercapture: cleatPointerThumbEvent
487
+ })
488
+ ]),
489
+ h(VxeLoadingComponent, {
490
+ class: 'vxe-scrollbar--loading',
491
+ modelValue: loading
492
+ })
493
+ ])
494
+ }
495
+
496
+ const reFlag = ref(0)
497
+
498
+ watch(() => props.height, () => {
499
+ reFlag.value++
500
+ })
501
+ watch(() => props.width, () => {
502
+ reFlag.value++
503
+ })
504
+ watch(() => props.minHeight, () => {
505
+ reFlag.value++
506
+ })
507
+ watch(() => props.minWidth, () => {
508
+ reFlag.value++
509
+ })
510
+ watch(() => props.maxHeight, () => {
511
+ reFlag.value++
512
+ })
513
+ watch(() => props.maxWidth, () => {
514
+ reFlag.value++
515
+ })
516
+ watch(() => props.native, () => {
517
+ reFlag.value++
518
+ })
519
+ watch(() => props.syncResize, () => {
520
+ reFlag.value++
521
+ })
522
+ watch(reFlag, () => {
523
+ $xeScrollbar.recalculate().then(() => {
524
+ $xeScrollbar.recalculate()
525
+ })
526
+ })
527
+
528
+ onMounted(() => {
529
+ const { autoResize } = props
530
+ const viewEl = refViewElem.value
531
+ const viewInnerEl = refViewInnerElem.value
532
+ if (autoResize) {
533
+ const resizeObserver = globalResize.create(() => {
534
+ if (props.autoResize) {
535
+ reFlag.value++
536
+ }
537
+ })
538
+ if (viewEl) {
539
+ resizeObserver.observe(viewEl)
540
+ }
541
+ if (viewInnerEl) {
542
+ resizeObserver.observe(viewInnerEl)
543
+ }
544
+ internalData.resizeObserver = resizeObserver
545
+ }
546
+
547
+ reFlag.value++
548
+ })
549
+
550
+ onBeforeUnmount(() => {
551
+ const { resizeObserver } = internalData
552
+ if (resizeObserver) {
553
+ resizeObserver.disconnect()
554
+ }
555
+ })
556
+
557
+ $xeScrollbar.renderVN = renderVN
558
+
559
+ return $xeScrollbar
560
+ },
561
+ render () {
562
+ return this.renderVN()
563
+ }
564
+ })
@@ -0,0 +1,57 @@
1
+ /**
2
+ * 计算滚动条滑块的长度
3
+ */
4
+ export function getThumbSize (viewportSize: number, contentSize: number, trackSize: number) {
5
+ if (contentSize <= viewportSize) {
6
+ return 0
7
+ }
8
+ const ratio = viewportSize / contentSize
9
+ const ideal = trackSize * ratio
10
+ return Math.max(20, Math.min(ideal, trackSize))
11
+ }
12
+
13
+ /**
14
+ * 计算滚动条滑块的偏移位置
15
+ */
16
+ export function getThumbOffsetSize (offsetSize: number, viewportSize: number, contentSize: number, trackSize: number, thumbSize: number) {
17
+ const maxScroll = contentSize - viewportSize
18
+ if (maxScroll <= 0) {
19
+ return 0
20
+ }
21
+ const maxThumbOffset = trackSize - thumbSize
22
+ if (maxThumbOffset <= 0) {
23
+ return 0
24
+ }
25
+ const clamped = Math.min(Math.max(offsetSize, 0), maxScroll)
26
+ const ratio = clamped / maxScroll
27
+ return ratio * maxThumbOffset
28
+ }
29
+
30
+ /**
31
+ * 根据点击轨道的位置,计算滑块的偏移位置
32
+ */
33
+ export function getScrollFromClick (clickPosition: number, viewportSize: number, contentSize: number, trackSize: number, thumbSize: number) {
34
+ const maxThumbOffset = trackSize - thumbSize
35
+ const maxScroll = contentSize - viewportSize
36
+ if (maxScroll <= 0 || maxThumbOffset <= 0) {
37
+ return 0
38
+ }
39
+ let thumbOffset = clickPosition - thumbSize / 2
40
+ thumbOffset = Math.min(Math.max(thumbOffset, 0), maxThumbOffset)
41
+ const scrollOffset = (thumbOffset / maxThumbOffset) * maxScroll
42
+ return scrollOffset
43
+ }
44
+
45
+ /**
46
+ * 拖拽 thumb 时,根据鼠标位置计算滑块的偏移位置
47
+ */
48
+ export function getScrollFromDrag (pointerPosition: number, dragOffset: number, viewportSize: number, contentSize: number, trackSize: number, thumbSize: number) {
49
+ const maxScroll = contentSize - viewportSize
50
+ const maxThumbOffset = trackSize - thumbSize
51
+ if (maxScroll <= 0 || maxThumbOffset <= 0) {
52
+ return 0
53
+ }
54
+ let thumbOffset = pointerPosition - dragOffset
55
+ thumbOffset = Math.min(Math.max(thumbOffset, 0), maxThumbOffset)
56
+ return (thumbOffset / maxThumbOffset) * maxScroll
57
+ }
@@ -353,6 +353,15 @@ setConfig({
353
353
  rate: {},
354
354
  result: {},
355
355
  row: {},
356
+ scrollbar: {
357
+ autoResize: true,
358
+ xConfig: {
359
+ // visible: 'visible'
360
+ },
361
+ yConfig: {
362
+ // visible: 'visible'
363
+ }
364
+ },
356
365
  segmented: {},
357
366
  select: {
358
367
  emptyValue: null,
package/styles/all.scss CHANGED
@@ -66,6 +66,7 @@
66
66
  @use './components/rate.scss';
67
67
  @use './components/result.scss';
68
68
  @use './components/row.scss';
69
+ @use './components/scrollbar.scss';
69
70
  @use './components/segmented.scss';
70
71
  @use './components/select.scss';
71
72
  @use './components/split.scss';