oxy-uni-ui 2.1.0 → 2.1.1

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 (94) hide show
  1. package/attributes.json +1 -1
  2. package/components/common/abstracts/variable.scss +132 -98
  3. package/components/common/util.ts +25 -0
  4. package/components/composables/useDynamicVirtualScroll.ts +80 -0
  5. package/components/oxy-action-sheet/index.scss +6 -6
  6. package/components/oxy-backtop/index.scss +1 -1
  7. package/components/oxy-badge/index.scss +2 -2
  8. package/components/oxy-button/index.scss +3 -6
  9. package/components/oxy-calendar/index.scss +2 -2
  10. package/components/oxy-calendar/oxy-calendar.vue +3 -3
  11. package/components/oxy-calendar-view/monthPanel/month-panel.vue +72 -37
  12. package/components/oxy-calendar-view/monthPanel/types.ts +43 -1
  13. package/components/oxy-calendar-view/types.ts +1 -1
  14. package/components/oxy-calendar-view/utils.ts +12 -1
  15. package/components/oxy-calendar-view/yearPanel/types.ts +36 -2
  16. package/components/oxy-calendar-view/yearPanel/year-panel.vue +64 -45
  17. package/components/oxy-card/index.scss +4 -4
  18. package/components/oxy-cell/index.scss +1 -1
  19. package/components/oxy-cell-group/index.scss +2 -2
  20. package/components/oxy-checkbox/index.scss +73 -218
  21. package/components/oxy-collapse/index.scss +1 -1
  22. package/components/oxy-collapse-item/index.scss +2 -2
  23. package/components/oxy-corner/index.scss +3 -3
  24. package/components/oxy-count-to/oxy-count-to.vue +3 -3
  25. package/components/oxy-count-to/types.ts +1 -1
  26. package/components/oxy-date-strip-item/index.scss +4 -4
  27. package/components/oxy-datetime-picker/types.ts +1 -1
  28. package/components/oxy-datetime-picker-view/types.ts +2 -2
  29. package/components/oxy-fab/index.scss +1 -5
  30. package/components/oxy-file-list/index.scss +2 -2
  31. package/components/oxy-footer/index.scss +2 -2
  32. package/components/oxy-footer/oxy-footer.vue +2 -3
  33. package/components/oxy-form-item/index.scss +0 -5
  34. package/components/oxy-grid/oxy-grid.vue +1 -1
  35. package/components/oxy-grid-item/index.scss +1 -1
  36. package/components/oxy-guidance/index.scss +2 -2
  37. package/components/oxy-img/index.scss +2 -2
  38. package/components/oxy-img-cropper/index.scss +0 -2
  39. package/components/oxy-img-lazy/index.scss +0 -1
  40. package/components/oxy-index-anchor/index.scss +3 -3
  41. package/components/oxy-input/index.scss +2 -2
  42. package/components/oxy-input-number/index.scss +21 -3
  43. package/components/oxy-input-number/oxy-input-number.vue +9 -1
  44. package/components/oxy-keyboard/index.scss +1 -1
  45. package/components/oxy-link/index.scss +11 -10
  46. package/components/oxy-loading/index.scss +1 -1
  47. package/components/oxy-loadmore/index.scss +1 -1
  48. package/components/oxy-message-box/index.scss +7 -7
  49. package/components/oxy-navbar/index.scss +1 -1
  50. package/components/oxy-navbar/oxy-navbar.vue +2 -3
  51. package/components/oxy-password-input/index.scss +4 -4
  52. package/components/oxy-picker/types.ts +1 -1
  53. package/components/oxy-picker-view/oxy-picker-view.vue +8 -5
  54. package/components/oxy-picker-view/types.ts +2 -2
  55. package/components/oxy-progress/index.scss +2 -2
  56. package/components/oxy-radio/index.scss +8 -4
  57. package/components/oxy-radio-group/index.scss +0 -1
  58. package/components/oxy-rich-text/index.scss +2 -6
  59. package/components/oxy-rich-text/mp-html/mp-html.d.ts +2 -0
  60. package/components/oxy-rich-text/mp-html/mp-html.vue +2 -1
  61. package/components/oxy-rich-text/mp-html/node/node.vue +23 -0
  62. package/components/oxy-rich-text/mp-html/parser.js +6 -6
  63. package/components/oxy-rich-text/oxy-rich-text.vue +23 -0
  64. package/components/oxy-search/index.scss +1 -1
  65. package/components/oxy-segmented/index.scss +4 -8
  66. package/components/oxy-select/index.scss +6 -6
  67. package/components/oxy-sidebar-item/index.scss +20 -11
  68. package/components/oxy-slider/index.scss +4 -5
  69. package/components/oxy-sort-button/index.scss +3 -5
  70. package/components/oxy-splitter-panel/index.scss +8 -8
  71. package/components/oxy-step/index.scss +9 -9
  72. package/components/oxy-swiper-nav/index.scss +2 -2
  73. package/components/oxy-switch/index.scss +3 -3
  74. package/components/oxy-tab/index.scss +8 -2
  75. package/components/oxy-tabbar/index.scss +3 -3
  76. package/components/oxy-tabbar/oxy-tabbar.vue +3 -3
  77. package/components/oxy-table/index.scss +0 -1
  78. package/components/oxy-table-col/index.scss +1 -2
  79. package/components/oxy-tabs/index.scss +3 -3
  80. package/components/oxy-tag/index.scss +4 -4
  81. package/components/oxy-text/index.scss +1 -1
  82. package/components/oxy-textarea/index.scss +2 -6
  83. package/components/oxy-toast/index.scss +1 -1
  84. package/components/oxy-tree/index.scss +31 -11
  85. package/components/oxy-tree/oxy-tree.vue +113 -2
  86. package/components/oxy-tree/types.ts +1 -0
  87. package/components/oxy-upload/index.scss +3 -3
  88. package/components/oxy-video-preview/index.scss +3 -3
  89. package/components/oxy-virtual-scroll/index.scss +1 -1
  90. package/components/oxy-voice-player/index.scss +36 -36
  91. package/components/oxy-watermark/index.scss +1 -1
  92. package/package.json +1 -1
  93. package/tags.json +1 -1
  94. package/web-types.json +1 -1
@@ -0,0 +1,80 @@
1
+ import { ref, computed, type Ref } from 'vue'
2
+
3
+ export interface DynamicVirtualScrollItem {
4
+ top: number
5
+ height: number
6
+ [key: string]: any
7
+ }
8
+
9
+ export interface UseDynamicVirtualScrollOptions<T extends DynamicVirtualScrollItem> {
10
+ data: Ref<T[]>
11
+ scrollTop: Ref<number>
12
+ viewportHeight: Ref<number>
13
+ buffer?: number
14
+ }
15
+
16
+ export function useDynamicVirtualScroll<T extends DynamicVirtualScrollItem>(options: UseDynamicVirtualScrollOptions<T>) {
17
+ const { data, scrollTop, viewportHeight, buffer = 0 } = options
18
+
19
+ const visibleData = computed(() => {
20
+ const st = scrollTop.value
21
+ const sh = viewportHeight.value
22
+ const buf = buffer || sh // 默认上下多预留一屏高度
23
+
24
+ const minTop = st - buf
25
+ const maxTop = st + sh + buf
26
+
27
+ // 二分查找第一个进入可视区的元素
28
+ let left = 0
29
+ let right = data.value.length - 1
30
+ let startIndex = 0
31
+
32
+ while (left <= right) {
33
+ const mid = Math.floor((left + right) / 2)
34
+ const item = data.value[mid]
35
+ if (item.top + item.height > minTop) {
36
+ startIndex = mid
37
+ right = mid - 1
38
+ } else {
39
+ left = mid + 1
40
+ }
41
+ }
42
+
43
+ // 从 startIndex 往后取,直到超出可视区
44
+ const result = []
45
+ for (let i = startIndex; i < data.value.length; i++) {
46
+ const item = data.value[i]
47
+ if (item.top < maxTop) {
48
+ result.push({ ...item, index: i })
49
+ } else {
50
+ break
51
+ }
52
+ }
53
+
54
+ return result
55
+ })
56
+
57
+ const getTargetIndex = (st: number) => {
58
+ let left = 0
59
+ let right = data.value.length - 1
60
+ let targetIndex = 0
61
+
62
+ while (left <= right) {
63
+ const mid = Math.floor((left + right) / 2)
64
+ const item = data.value[mid]
65
+ if (st < item.top + item.height) {
66
+ targetIndex = mid
67
+ right = mid - 1
68
+ } else {
69
+ left = mid + 1
70
+ }
71
+ }
72
+
73
+ return targetIndex
74
+ }
75
+
76
+ return {
77
+ visibleData,
78
+ getTargetIndex
79
+ }
80
+ }
@@ -57,7 +57,7 @@
57
57
  }
58
58
 
59
59
  @include b(action-sheet) {
60
- background-color: $-color-white;
60
+ background-color: $-action-sheet-bg;
61
61
  padding-bottom: 2rpx;
62
62
  margin-bottom: var(--window-bottom);
63
63
 
@@ -111,7 +111,7 @@
111
111
  line-height: initial;
112
112
  }
113
113
  }
114
-
114
+
115
115
  @include edeep(action-loading){
116
116
  width: $-action-sheet-loading-size;
117
117
  height: $-action-sheet-loading-size;
@@ -169,7 +169,7 @@
169
169
  color: $-action-sheet-close-color;
170
170
  font-size: $-action-sheet-close-fs;
171
171
  transform: rotate(-45deg);
172
- line-height: 1.1;
172
+ line-height: $-line-height-tight;
173
173
  }
174
174
 
175
175
  @include e(panels) {
@@ -181,7 +181,7 @@
181
181
  }
182
182
 
183
183
  &:last-of-type {
184
- margin-bottom: 24rpx;
184
+ margin-bottom: $-spacing-24;
185
185
  }
186
186
  }
187
187
 
@@ -203,13 +203,13 @@
203
203
  width: $-action-sheet-panel-img-fs;
204
204
  height: $-action-sheet-panel-img-fs;
205
205
  margin: 0 auto;
206
- margin-bottom: 16rpx;
206
+ margin-bottom: $-spacing-16;
207
207
  border-radius: $-action-sheet-panel-img-radius;
208
208
  }
209
209
 
210
210
  @include e(panel-title) {
211
211
  font-size: $-action-sheet-subname-fs;
212
- line-height: 1.2;
212
+ line-height: $-line-height-base;
213
213
  text-align: center;
214
214
  color: $-action-sheet-color;
215
215
  @include lineEllipsis;
@@ -16,7 +16,7 @@
16
16
  }
17
17
 
18
18
  @include when(circle) {
19
- border-radius: 50%;
19
+ border-radius: $-radius-circle;
20
20
  }
21
21
 
22
22
  @include when(square) {
@@ -28,7 +28,7 @@
28
28
  text-align: center;
29
29
  white-space: nowrap;
30
30
  border: $-badge-border;
31
- font-weight: 500;
31
+ font-weight: $-fw-medium;
32
32
 
33
33
  @include when(fixed) {
34
34
  position: absolute;
@@ -41,7 +41,7 @@
41
41
  height: $-badge-dot-size;
42
42
  width: $-badge-dot-size;
43
43
  padding: 0;
44
- border-radius: 50%;
44
+ border-radius: $-radius-circle;
45
45
  }
46
46
 
47
47
  @each $type in (primary, success, warning, info, danger) {
@@ -47,7 +47,6 @@
47
47
  display: inline-block;
48
48
  outline: none;
49
49
  -webkit-appearance: none;
50
- outline: none;
51
50
  background: transparent;
52
51
  box-sizing: border-box;
53
52
  border: none;
@@ -109,8 +108,6 @@
109
108
  background-repeat: no-repeat;
110
109
  }
111
110
 
112
- @include when(loading) {}
113
-
114
111
  @include when(primary) {
115
112
  background: $-button-primary-bg-color;
116
113
  color: $-button-primary-color;
@@ -161,7 +158,7 @@
161
158
 
162
159
  @include when(icon) {
163
160
  min-width: 0;
164
- border-radius: 50%;
161
+ border-radius: $-radius-circle;
165
162
  }
166
163
 
167
164
  @include when(text) {
@@ -223,7 +220,7 @@
223
220
 
224
221
  @include when(plain) {
225
222
  background: $-button-plain-bg-color;
226
- border: 1px solid currentColor;
223
+ border: #{$-border-width-base} solid currentColor;
227
224
 
228
225
  @include when(primary) {
229
226
  color: $-button-primary-bg-color;
@@ -295,7 +292,7 @@
295
292
  width: $-button-icon-size;
296
293
  height: $-button-icon-size;
297
294
  padding: 0;
298
- border-radius: 50%;
295
+ border-radius: $-radius-circle;
299
296
  color: $-button-icon-color;
300
297
 
301
298
  &::after {
@@ -71,7 +71,7 @@
71
71
  }
72
72
 
73
73
  @include edeep(tag) {
74
- margin-right: 16rpx;
74
+ margin-right: $-spacing-16;
75
75
  }
76
76
 
77
77
  @include e(view) {
@@ -91,7 +91,7 @@
91
91
  font-size: $-fs-content;
92
92
 
93
93
  @include when(monthrange) {
94
- padding-bottom: 24rpx;
94
+ padding-bottom: $-spacing-24;
95
95
  box-shadow: $-calendar-panel-shadow-light;
96
96
  }
97
97
  }
@@ -238,7 +238,7 @@ const emit = defineEmits(['cancel', 'change', 'update:modelValue', 'confirm', 'o
238
238
  const pickerShow = ref<boolean>(false)
239
239
  const calendarValue = ref<null | number | number[]>(null)
240
240
  const lastCalendarValue = ref<null | number | number[]>(null)
241
- const panelHeight = ref<number>(338)
241
+ const panelHeight = ref<number>(676)
242
242
  const confirmBtnDisabled = ref<boolean>(true)
243
243
  const currentTab = ref<number>(0)
244
244
  const lastTab = ref<number>(0)
@@ -294,7 +294,7 @@ watch(
294
294
  const index = newValue.indexOf('range') > -1 ? rangeTabs.indexOf(newValue) || 0 : tabs.indexOf(newValue)
295
295
  currentTab.value = index
296
296
  }
297
- panelHeight.value = props.showConfirm ? 338 : 400
297
+ panelHeight.value = props.showConfirm ? 676 : 800
298
298
  currentType.value = deepClone(newValue)
299
299
  },
300
300
  {
@@ -306,7 +306,7 @@ watch(
306
306
  watch(
307
307
  () => props.showConfirm,
308
308
  (val) => {
309
- panelHeight.value = val ? 338 : 400
309
+ panelHeight.value = val ? 676 : 800
310
310
  },
311
311
  {
312
312
  deep: true,
@@ -8,27 +8,34 @@
8
8
  </view>
9
9
  <scroll-view
10
10
  :class="`oxy-month-panel__container ${!!timeType ? 'oxy-month-panel__container--time' : ''}`"
11
- :style="`height: ${unitConvert(scrollHeight, 0, { output: 'px' })}`"
11
+ :style="`height: ${scrollHeight}px`"
12
12
  scroll-y
13
13
  @scroll="monthScroll"
14
14
  :scroll-top="scrollTop"
15
15
  >
16
- <view v-for="(item, index) in months" :key="index" :id="`month${index}`">
17
- <month
18
- :type="type"
19
- :date="item.date"
20
- :value="value"
21
- :min-date="minDate"
22
- :max-date="maxDate"
23
- :first-day-of-week="firstDayOfWeek"
24
- :formatter="formatter"
25
- :max-range="maxRange"
26
- :range-prompt="rangePrompt"
27
- :allow-same-day="allowSameDay"
28
- :default-time="defaultTime"
29
- :showTitle="index !== 0"
30
- @change="handleDateChange"
31
- />
16
+ <view class="oxy-month-panel__list" :style="`height: ${totalHeight}px; position: relative;`">
17
+ <view
18
+ v-for="item in visibleMonths"
19
+ :key="item.date"
20
+ :id="`month${item.index}`"
21
+ :style="`position: absolute; top: ${item.top}px; width: 100%;`"
22
+ >
23
+ <month
24
+ :type="type"
25
+ :date="item.date"
26
+ :value="value"
27
+ :min-date="minDate"
28
+ :max-date="maxDate"
29
+ :first-day-of-week="firstDayOfWeek"
30
+ :formatter="formatter"
31
+ :max-range="maxRange"
32
+ :range-prompt="rangePrompt"
33
+ :allow-same-day="allowSameDay"
34
+ :default-time="defaultTime"
35
+ :showTitle="item.index !== 0"
36
+ @change="handleDateChange"
37
+ />
38
+ </view>
32
39
  </view>
33
40
  </scroll-view>
34
41
  <view v-if="timeType" class="oxy-month-panel__time">
@@ -65,10 +72,23 @@ export default {
65
72
  import OxyPickerView from '../../oxy-picker-view/oxy-picker-view.vue'
66
73
  import { computed, ref, watch, onMounted } from 'vue'
67
74
  import { debounce, isArray, isEqual, isNumber, pause, unitConvert } from '../../common/util'
68
- import { compareMonth, formatMonthTitle, getMonthEndDay, getMonths, getTimeData, getWeekLabel } from '../utils'
75
+ import {
76
+ compareMonth,
77
+ formatMonthTitle,
78
+ getMonthEndDay,
79
+ getMonths,
80
+ getTimeData,
81
+ getWeekLabel,
82
+ designPxToRuntimePx,
83
+ MONTH_ROW_HEIGHT,
84
+ MONTH_ROW_GAP,
85
+ MONTH_TITLE_HEIGHT,
86
+ TIME_PICKER_HEIGHT
87
+ } from '../utils'
69
88
  import Month from '../month/month.vue'
70
89
  import { monthPanelProps, type MonthInfo, type MonthPanelTimeType, type MonthPanelExpose } from './types'
71
90
  import { useTranslate } from '../../composables/useTranslate'
91
+ import { useDynamicVirtualScroll } from '../../composables/useDynamicVirtualScroll'
72
92
  import type { CalendarItem } from '../types'
73
93
 
74
94
  const props = defineProps(monthPanelProps)
@@ -77,18 +97,13 @@ const emit = defineEmits(['change', 'pickstart', 'pickend'])
77
97
  const { translate } = useTranslate('calendar-view')
78
98
 
79
99
  const scrollTop = ref<number>(0) // 滚动位置
100
+ const currentScrollTop = ref<number>(0) // 当前虚拟渲染滚动位置
80
101
  const scrollIndex = ref<number>(0) // 当前显示的月份索引
81
102
  const timeValue = ref<number[]>([]) // 当前选中的时分秒
82
103
 
83
104
  const timeType = ref<MonthPanelTimeType>('') // 当前时间类型,是开始还是结束
84
105
  const innerValue = ref<string | number | (number | null)[]>('') // 内部保存一个值,用于判断新老值,避免监听器触发
85
106
 
86
- const designPxToRuntimePx = (designPx: number): number => unitConvert(`${designPx * 2}rpx`)
87
- const MONTH_ROW_HEIGHT = designPxToRuntimePx(64)
88
- const MONTH_ROW_GAP = designPxToRuntimePx(4)
89
- const MONTH_TITLE_HEIGHT = designPxToRuntimePx(45)
90
- const TIME_PICKER_HEIGHT = designPxToRuntimePx(125)
91
-
92
107
  const handleChange = debounce((value) => {
93
108
  emit('change', {
94
109
  value
@@ -139,23 +154,44 @@ const weekLabel = computed(() => {
139
154
  // 滚动区域的高度
140
155
  const scrollHeight = computed(() => {
141
156
  const panelHeight = designPxToRuntimePx(props.panelHeight)
142
- const scrollHeight: number = timeType.value ? panelHeight - TIME_PICKER_HEIGHT : panelHeight
157
+ const scrollHeight: number = panelHeight - (props.showPanelTitle ? MONTH_TITLE_HEIGHT : 0) - (timeType.value ? TIME_PICKER_HEIGHT : 0)
143
158
  return scrollHeight
144
159
  })
145
160
 
146
161
  // 月份日期和月份高度
147
162
  const months = computed<MonthInfo[]>(() => {
163
+ let top = 0
148
164
  return getMonths(props.minDate, props.maxDate).map((month, index) => {
149
165
  const offset = (7 + new Date(month).getDay() - props.firstDayOfWeek) % 7
150
166
  const totalDay = getMonthEndDay(new Date(month).getFullYear(), new Date(month).getMonth() + 1)
151
167
  const rows = Math.ceil((offset + totalDay) / 7)
168
+ const height = rows * MONTH_ROW_HEIGHT + (rows - 1) * MONTH_ROW_GAP + (index === 0 ? 0 : MONTH_TITLE_HEIGHT)
169
+ const currentTop = top
170
+ top += height
152
171
  return {
153
- height: rows * MONTH_ROW_HEIGHT + (rows - 1) * MONTH_ROW_GAP + (index === 0 ? 0 : MONTH_TITLE_HEIGHT),
172
+ height,
173
+ top: currentTop,
154
174
  date: month
155
175
  }
156
176
  })
157
177
  })
158
178
 
179
+ const totalHeight = computed(() => {
180
+ if (months.value.length === 0) return 0
181
+ const last = months.value[months.value.length - 1]
182
+ return last.top + last.height
183
+ })
184
+
185
+ // 滚动区域的高度(用于计算可视区域)
186
+ const viewportHeight = computed(() => designPxToRuntimePx(props.panelHeight))
187
+
188
+ // 引入动态虚拟滚动 Hook
189
+ const { visibleData: visibleMonths, getTargetIndex } = useDynamicVirtualScroll<MonthInfo>({
190
+ data: months,
191
+ scrollTop: currentScrollTop,
192
+ viewportHeight
193
+ })
194
+
159
195
  watch(
160
196
  () => props.type,
161
197
  (val) => {
@@ -229,8 +265,13 @@ async function scrollIntoView() {
229
265
  }
230
266
  scrollTop.value = 0
231
267
  if (top > 0) {
268
+ const targetTop = top + (activeMonthIndex > 0 && compareMonth(months.value[0].date, activeDate) !== 0 ? MONTH_TITLE_HEIGHT : 0)
269
+ currentScrollTop.value = targetTop
270
+ // 在首次渲染前同步 currentScrollTop,避免闪烁
271
+ scrollTop.value = targetTop
232
272
  await pause()
233
- scrollTop.value = top + (activeMonthIndex > 0 ? MONTH_TITLE_HEIGHT : 0)
273
+ } else {
274
+ currentScrollTop.value = 0
234
275
  }
235
276
  }
236
277
  /**
@@ -351,8 +392,9 @@ const monthScroll = (event: { detail: { scrollTop: number } }) => {
351
392
  if (months.value.length <= 1) {
352
393
  return
353
394
  }
354
- const scrollTop = Math.max(0, event.detail.scrollTop)
355
- doSetSubtitle(scrollTop)
395
+ const st = Math.max(0, event.detail.scrollTop)
396
+ currentScrollTop.value = st
397
+ doSetSubtitle(st)
356
398
  }
357
399
 
358
400
  /**
@@ -360,14 +402,7 @@ const monthScroll = (event: { detail: { scrollTop: number } }) => {
360
402
  * scrollTop 滚动条位置
361
403
  */
362
404
  function doSetSubtitle(scrollTop: number) {
363
- let height: number = 0 // 月份高度和
364
- for (let index = 0; index < months.value.length; index++) {
365
- height = height + months.value[index].height
366
- if (scrollTop < height) {
367
- scrollIndex.value = index
368
- return
369
- }
370
- }
405
+ scrollIndex.value = getTargetIndex(scrollTop)
371
406
  }
372
407
 
373
408
  defineExpose<MonthPanelExpose>({
@@ -8,25 +8,67 @@ import type { CalendarFormatter, CalendarTimeFilter, CalendarType } from '../typ
8
8
  export interface MonthInfo {
9
9
  date: number
10
10
  height: number
11
+ top: number
11
12
  }
12
13
 
13
14
  export const monthPanelProps = {
15
+ /**
16
+ * 日期类型
17
+ */
14
18
  type: makeRequiredProp(String as PropType<CalendarType>),
19
+ /**
20
+ * 选中值
21
+ */
15
22
  value: makeRequiredProp([Number, Array, null] as PropType<number | (number | null)[] | null>),
23
+ /**
24
+ * 最小日期时间戳
25
+ */
16
26
  minDate: makeRequiredProp(Number),
27
+ /**
28
+ * 最大日期时间戳
29
+ */
17
30
  maxDate: makeRequiredProp(Number),
31
+ /**
32
+ * 一周的第一天
33
+ */
18
34
  firstDayOfWeek: makeRequiredProp(Number),
35
+ /**
36
+ * 格式化函数
37
+ */
19
38
  formatter: Function as PropType<CalendarFormatter>,
39
+ /**
40
+ * 最大范围限制
41
+ */
20
42
  maxRange: Number,
43
+ /**
44
+ * 超出范围提示
45
+ */
21
46
  rangePrompt: String,
47
+ /**
48
+ * 是否允许选择同一天
49
+ */
22
50
  allowSameDay: makeBooleanProp(false),
51
+ /**
52
+ * 是否展示面板标题
53
+ */
23
54
  showPanelTitle: makeBooleanProp(false),
55
+ /**
56
+ * 默认时间
57
+ */
24
58
  defaultTime: {
25
59
  type: [Array] as PropType<Array<number[]>>
26
60
  },
61
+ /**
62
+ * 面板高度
63
+ */
27
64
  panelHeight: makeRequiredProp(Number),
28
- // type 为 'datetime' 或 'datetimerange' 时有效,用于过滤时间选择器的数据
65
+ /**
66
+ * 用于过滤时间选择器的数据
67
+ */
29
68
  timeFilter: Function as PropType<CalendarTimeFilter>,
69
+ /**
70
+ * 是否隐藏秒
71
+ */
30
72
  hideSecond: makeBooleanProp(false),
31
73
  /**
32
74
  * 是否在手指松开时立即触发picker-view的 change 事件。若不开启则会在滚动动画结束后触发 change 事件,1.2.25版本起提供,仅微信小程序和支付宝小程序支持。
@@ -53,7 +53,7 @@ export const calendarViewProps = {
53
53
  /**
54
54
  * 可滚动面板的高度
55
55
  */
56
- panelHeight: makeNumberProp(378),
56
+ panelHeight: makeNumberProp(756),
57
57
  /**
58
58
  * type 为 'datetime' 或 'datetimerange' 时有效,用于过滤时间选择器的数据
59
59
  */
@@ -1,10 +1,21 @@
1
1
  import { computed } from 'vue'
2
2
  import dayjs from '../../dayjs'
3
- import { isArray, isFunction, padZero } from '../common/util'
3
+ import { isArray, isFunction, padZero, unitConvert } from '../common/util'
4
4
  import { useTranslate } from '../composables/useTranslate'
5
5
  import type { CalendarDayType, CalendarItem, CalendarTimeFilter, CalendarType } from './types'
6
6
  const { translate } = useTranslate('calendar-view')
7
7
 
8
+ export const designPxToRuntimePx = (designPx: number): number => unitConvert(`${designPx}rpx`)
9
+ export const MONTH_ROW_HEIGHT = designPxToRuntimePx(128)
10
+ export const MONTH_ROW_GAP = designPxToRuntimePx(8)
11
+ export const MONTH_TITLE_HEIGHT = designPxToRuntimePx(90)
12
+ export const YEAR_TITLE_HEIGHT = designPxToRuntimePx(90)
13
+ export const TIME_PICKER_HEIGHT = designPxToRuntimePx(250)
14
+ export const PANEL_EXTRA_WITH_TITLE = designPxToRuntimePx(52)
15
+ export const PANEL_EXTRA_NO_TITLE = designPxToRuntimePx(32)
16
+ export const YEAR_HEIGHT_WITHOUT_TITLE = MONTH_ROW_HEIGHT * 3 + MONTH_ROW_GAP * 2
17
+ export const YEAR_HEIGHT_WITH_TITLE = YEAR_HEIGHT_WITHOUT_TITLE + YEAR_TITLE_HEIGHT
18
+
8
19
  const weeks = computed(() => {
9
20
  return [
10
21
  translate('weeks.sun'),
@@ -3,26 +3,60 @@ import { makeBooleanProp, makeRequiredProp } from '../../common/props'
3
3
  import type { CalendarFormatter, CalendarType } from '../types'
4
4
 
5
5
  /**
6
- * 月份信息
6
+ * 年份信息
7
7
  */
8
8
  export interface YearInfo {
9
9
  date: number
10
10
  height: number
11
+ top: number
11
12
  }
12
13
 
13
14
  export const yearPanelProps = {
15
+ /**
16
+ * 日期类型
17
+ */
14
18
  type: makeRequiredProp(String as PropType<CalendarType>),
15
- value: makeRequiredProp([Number, Array] as PropType<number | (number | null)[] | null>),
19
+ /**
20
+ * 选中值
21
+ */
22
+ value: makeRequiredProp([Number, Array, null] as PropType<number | (number | null)[] | null>),
23
+ /**
24
+ * 最小日期时间戳
25
+ */
16
26
  minDate: makeRequiredProp(Number),
27
+ /**
28
+ * 最大日期时间戳
29
+ */
17
30
  maxDate: makeRequiredProp(Number),
31
+ /**
32
+ * 格式化函数
33
+ */
18
34
  formatter: Function as PropType<CalendarFormatter>,
35
+ /**
36
+ * 最大范围限制
37
+ */
19
38
  maxRange: Number,
39
+ /**
40
+ * 超出范围提示
41
+ */
20
42
  rangePrompt: String,
43
+ /**
44
+ * 是否允许选择同一天
45
+ */
21
46
  allowSameDay: makeBooleanProp(false),
47
+ /**
48
+ * 是否展示标题
49
+ */
22
50
  showPanelTitle: makeBooleanProp(false),
51
+ /**
52
+ * 默认时间
53
+ */
23
54
  defaultTime: {
24
55
  type: [Array] as PropType<Array<number[]>>
25
56
  },
57
+ /**
58
+ * 面板高度
59
+ */
26
60
  panelHeight: makeRequiredProp(Number)
27
61
  }
28
62