oxy-uni-ui 1.2.3 → 2.1.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.
- package/attributes.json +1 -1
- package/components/common/abstracts/variable.scss +512 -343
- package/components/common/util.ts +185 -32
- package/components/composables/index.ts +1 -0
- package/components/composables/usePopover.ts +24 -20
- package/components/composables/useVirtualScroll.ts +48 -21
- package/components/composables/useWindowResize.ts +35 -0
- package/components/oxy-action-sheet/index.scss +24 -11
- package/components/oxy-action-sheet/oxy-action-sheet.vue +27 -19
- package/components/oxy-action-sheet/types.ts +7 -0
- package/components/oxy-backtop/index.scss +4 -4
- package/components/oxy-backtop/oxy-backtop.vue +9 -6
- package/components/oxy-backtop/types.ts +7 -7
- package/components/oxy-badge/index.scss +4 -4
- package/components/oxy-badge/oxy-badge.vue +3 -3
- package/components/oxy-badge/types.ts +2 -2
- package/components/oxy-button/index.scss +5 -5
- package/components/oxy-button/oxy-button.vue +5 -1
- package/components/oxy-calendar/index.scss +15 -15
- package/components/oxy-calendar/oxy-calendar.vue +1 -0
- package/components/oxy-calendar/types.ts +5 -0
- package/components/oxy-calendar-view/month/index.scss +4 -4
- package/components/oxy-calendar-view/month/types.ts +36 -0
- package/components/oxy-calendar-view/monthPanel/index.scss +7 -8
- package/components/oxy-calendar-view/monthPanel/month-panel.vue +14 -8
- package/components/oxy-calendar-view/year/index.scss +5 -5
- package/components/oxy-calendar-view/yearPanel/index.scss +4 -4
- package/components/oxy-calendar-view/yearPanel/year-panel.vue +21 -5
- package/components/oxy-card/index.scss +2 -2
- package/components/oxy-cell/index.scss +8 -8
- package/components/oxy-checkbox/index.scss +12 -12
- package/components/oxy-checkbox-group/index.scss +2 -2
- package/components/oxy-circle/oxy-circle.vue +10 -7
- package/components/oxy-circle/types.ts +5 -5
- package/components/oxy-col/oxy-col.vue +2 -2
- package/components/oxy-col-picker/index.scss +4 -4
- package/components/oxy-col-picker/oxy-col-picker.vue +6 -5
- package/components/oxy-col-picker/types.ts +7 -2
- package/components/oxy-collapse/index.scss +2 -2
- package/components/oxy-collapse-item/oxy-collapse-item.vue +3 -3
- package/components/oxy-corner/index.scss +33 -33
- package/components/oxy-count-to/oxy-count-to.vue +3 -3
- package/components/oxy-curtain/index.scss +15 -15
- package/components/oxy-curtain/oxy-curtain.vue +4 -2
- package/components/oxy-curtain/types.ts +6 -1
- package/components/oxy-date-strip/oxy-date-strip.vue +2 -2
- package/components/oxy-date-strip/types.ts +1 -1
- package/components/oxy-date-strip-item/index.scss +3 -3
- package/components/oxy-datetime-picker/index.scss +11 -11
- package/components/oxy-datetime-picker/oxy-datetime-picker.vue +1 -0
- package/components/oxy-datetime-picker/types.ts +5 -0
- package/components/oxy-drop-menu/index.scss +5 -5
- package/components/oxy-drop-menu/oxy-drop-menu.vue +3 -3
- package/components/oxy-drop-menu-item/index.scss +3 -3
- package/components/oxy-drop-menu-item/oxy-drop-menu-item.vue +4 -3
- package/components/oxy-drop-menu-item/types.ts +5 -0
- package/components/oxy-echarts/types.ts +6 -0
- package/components/oxy-fab/index.scss +8 -8
- package/components/oxy-fab/oxy-fab.vue +22 -3
- package/components/oxy-file-list/index.scss +30 -29
- package/components/oxy-file-list/oxy-file-list.vue +2 -2
- package/components/oxy-floating-panel/oxy-floating-panel.vue +13 -9
- package/components/oxy-floating-panel/{type.ts → types.ts} +8 -8
- package/components/oxy-footer/index.scss +19 -0
- package/components/oxy-footer/oxy-footer.vue +78 -0
- package/components/oxy-footer/types.ts +17 -0
- package/components/oxy-form-item/types.ts +22 -1
- package/components/oxy-gap/oxy-gap.vue +2 -2
- package/components/oxy-gap/types.ts +2 -2
- package/components/oxy-grid/oxy-grid.vue +1 -1
- package/components/oxy-grid/types.ts +1 -1
- package/components/oxy-grid-item/index.scss +1 -1
- package/components/oxy-grid-item/oxy-grid-item.vue +7 -5
- package/components/oxy-grid-item/types.ts +1 -1
- package/components/oxy-guidance/index.scss +75 -0
- package/components/oxy-guidance/oxy-guidance.vue +201 -0
- package/components/oxy-guidance/types.ts +33 -0
- package/components/oxy-icon/oxy-icon.vue +2 -2
- package/components/oxy-icon/types.ts +1 -1
- package/components/oxy-img/oxy-img.vue +4 -4
- package/components/oxy-img/types.ts +3 -3
- package/components/oxy-img-cropper/index.scss +23 -23
- package/components/oxy-img-cropper/oxy-img-cropper.vue +97 -52
- package/components/oxy-img-cropper/types.ts +2 -2
- package/components/oxy-img-lazy/oxy-img-lazy.vue +3 -3
- package/components/oxy-img-lazy/types.ts +3 -3
- package/components/oxy-index-anchor/index.scss +2 -2
- package/components/oxy-index-anchor/oxy-index-anchor.vue +2 -2
- package/components/oxy-index-anchor/{type.ts → types.ts} +3 -0
- package/components/oxy-index-bar/index.scss +3 -3
- package/components/oxy-index-bar/oxy-index-bar.vue +3 -3
- package/components/oxy-index-bar/{type.ts → types.ts} +2 -2
- package/components/oxy-input/index.scss +1 -1
- package/components/oxy-input-number/index.scss +5 -5
- package/components/oxy-input-number/oxy-input-number.vue +2 -2
- package/components/oxy-input-number/types.ts +3 -2
- package/components/oxy-keyboard/index.scss +5 -5
- package/components/oxy-keyboard/key/index.scss +3 -3
- package/components/oxy-keyboard/key/index.vue +2 -2
- package/components/oxy-keyboard/key/types.ts +15 -0
- package/components/oxy-keyboard/oxy-keyboard.vue +1 -0
- package/components/oxy-keyboard/types.ts +5 -0
- package/components/oxy-link/index.scss +2 -2
- package/components/oxy-list/oxy-list.vue +4 -3
- package/components/oxy-loading/oxy-loading.vue +8 -4
- package/components/oxy-loading/types.ts +1 -1
- package/components/oxy-loadmore/index.scss +3 -3
- package/components/oxy-long-press-menu/index.scss +93 -0
- package/components/oxy-long-press-menu/oxy-long-press-menu.vue +338 -0
- package/components/oxy-long-press-menu/types.ts +34 -0
- package/components/oxy-message-box/index.scss +12 -11
- package/components/oxy-message-box/oxy-message-box.vue +9 -2
- package/components/oxy-message-box/types.ts +9 -0
- package/components/oxy-navbar/index.scss +2 -2
- package/components/oxy-navbar/oxy-navbar.vue +58 -13
- package/components/oxy-navbar/types.ts +8 -1
- package/components/oxy-navbar-capsule/types.ts +3 -0
- package/components/oxy-notice-bar/index.scss +3 -3
- package/components/oxy-notice-bar/oxy-notice-bar.vue +9 -5
- package/components/oxy-notice-bar/types.ts +3 -3
- package/components/oxy-notify/index.ts +1 -0
- package/components/oxy-notify/oxy-notify.vue +3 -2
- package/components/oxy-notify/types.ts +7 -0
- package/components/oxy-pagination/index.scss +6 -5
- package/components/oxy-password-input/oxy-password-input.vue +2 -2
- package/components/oxy-password-input/types.ts +1 -1
- package/components/oxy-picker/index.scss +45 -2
- package/components/oxy-picker/oxy-picker.vue +100 -14
- package/components/oxy-picker/types.ts +29 -1
- package/components/oxy-picker-view/index.scss +4 -4
- package/components/oxy-picker-view/oxy-picker-view.vue +4 -4
- package/components/oxy-popover/index.scss +13 -13
- package/components/oxy-popup/index.scss +4 -4
- package/components/oxy-popup/oxy-popup.vue +35 -2
- package/components/oxy-popup/types.ts +8 -1
- package/components/oxy-progress/index.scss +3 -3
- package/components/oxy-qrcode/draw.ts +398 -0
- package/components/oxy-qrcode/index.scss +2 -0
- package/components/oxy-qrcode/oxy-qrcode.vue +124 -0
- package/components/oxy-qrcode/qrcode.ts +936 -0
- package/components/oxy-qrcode/types.ts +42 -0
- package/components/oxy-radio/index.scss +25 -19
- package/components/oxy-radio-group/index.scss +2 -2
- package/components/oxy-rate/types.ts +4 -4
- package/components/oxy-resize/index.scss +2 -2
- package/components/oxy-resize/oxy-resize.vue +4 -4
- package/components/oxy-resize/types.ts +3 -0
- package/components/oxy-rich-text/index.scss +37 -36
- package/components/oxy-rich-text/mp-html/card/card.vue +3 -3
- package/components/oxy-rich-text/mp-html/mp-html.vue +33 -24
- package/components/oxy-rich-text/mp-html/node/node.vue +30 -19
- package/components/oxy-rich-text/oxy-rich-text.vue +31 -31
- package/components/oxy-rich-text/types.ts +6 -1
- package/components/oxy-row/oxy-row.vue +3 -3
- package/components/oxy-row/types.ts +1 -1
- package/components/oxy-search/index.scss +7 -7
- package/components/oxy-segmented/index.scss +19 -16
- package/components/oxy-segmented/oxy-segmented.vue +23 -3
- package/components/oxy-select/index.scss +213 -89
- package/components/oxy-select/oxy-select.vue +106 -58
- package/components/oxy-select/types.ts +13 -1
- package/components/oxy-select-picker/index.scss +7 -7
- package/components/oxy-select-picker/oxy-select-picker.vue +1 -0
- package/components/oxy-select-picker/types.ts +2 -0
- package/components/oxy-sidebar-item/index.scss +2 -2
- package/components/oxy-signature/oxy-signature.vue +18 -10
- package/components/oxy-signature/types.ts +106 -13
- package/components/oxy-skeleton/index.scss +1 -1
- package/components/oxy-skeleton/oxy-skeleton.vue +6 -6
- package/components/oxy-skeleton/types.ts +1 -1
- package/components/oxy-slider/index.scss +6 -6
- package/components/oxy-sort-button/index.scss +8 -8
- package/components/oxy-splitter/index.scss +19 -0
- package/components/oxy-splitter/oxy-splitter.vue +409 -0
- package/components/oxy-splitter/types.ts +75 -0
- package/components/oxy-splitter-panel/index.scss +366 -0
- package/components/oxy-splitter-panel/oxy-splitter-panel.vue +432 -0
- package/components/oxy-splitter-panel/types.ts +63 -0
- package/components/oxy-status-tip/index.scss +4 -4
- package/components/oxy-status-tip/oxy-status-tip.vue +5 -5
- package/components/oxy-status-tip/types.ts +3 -3
- package/components/oxy-step/index.scss +16 -16
- package/components/oxy-sticky/oxy-sticky.vue +6 -6
- package/components/oxy-stream-render/oxy-stream-render.vue +230 -4
- package/components/oxy-stream-render/types.ts +4 -1
- package/components/oxy-swipe-action/oxy-swipe-action.vue +27 -2
- package/components/oxy-swiper/oxy-swiper.vue +6 -6
- package/components/oxy-swiper/types.ts +5 -5
- package/components/oxy-swiper-nav/index.scss +3 -3
- package/components/oxy-switch/index.scss +10 -10
- package/components/oxy-switch/oxy-switch.vue +2 -2
- package/components/oxy-switch/types.ts +1 -1
- package/components/oxy-tab/index.scss +11 -1
- package/components/oxy-tabbar/index.scss +2 -2
- package/components/oxy-tabbar/oxy-tabbar.vue +39 -10
- package/components/oxy-table/index.scss +8 -8
- package/components/oxy-table/oxy-table.vue +8 -6
- package/components/oxy-table/types.ts +2 -2
- package/components/oxy-table-col/index.scss +3 -3
- package/components/oxy-table-col/oxy-table-col.vue +3 -3
- package/components/oxy-table-col/types.ts +2 -2
- package/components/oxy-tabs/index.scss +52 -22
- package/components/oxy-tabs/oxy-tabs.vue +53 -19
- package/components/oxy-tabs/types.ts +15 -3
- package/components/oxy-tag/index.scss +111 -36
- package/components/oxy-text/index.scss +5 -1
- package/components/oxy-text/oxy-text.vue +76 -7
- package/components/oxy-text/types.ts +12 -0
- package/components/oxy-textarea/index.scss +6 -6
- package/components/oxy-toast/oxy-toast.vue +24 -8
- package/components/oxy-tooltip/index.scss +9 -9
- package/components/oxy-tree/index.scss +51 -15
- package/components/oxy-tree/oxy-tree.vue +13 -9
- package/components/oxy-tree/types.ts +12 -9
- package/components/oxy-upload/index.scss +23 -23
- package/components/oxy-upload/types.ts +2 -2
- package/components/oxy-verification-code/index.scss +6 -0
- package/components/oxy-verification-code/oxy-verification-code.vue +187 -0
- package/components/oxy-verification-code/types.ts +82 -0
- package/components/oxy-video-preview/index.scss +4 -4
- package/components/oxy-virtual-scroll/index.scss +5 -5
- package/components/oxy-virtual-scroll/oxy-virtual-scroll.vue +11 -7
- package/components/oxy-virtual-scroll/types.ts +14 -14
- package/components/oxy-voice-player/index.scss +937 -0
- package/components/oxy-voice-player/oxy-voice-player.vue +821 -0
- package/components/oxy-voice-player/types.ts +567 -0
- package/components/oxy-waterfall/oxy-waterfall.vue +6 -6
- package/components/oxy-waterfall/types.ts +6 -6
- package/components/oxy-watermark/oxy-watermark.vue +35 -13
- package/components/oxy-watermark/types.ts +14 -14
- package/global.d.ts +4 -0
- package/locale/lang/ar-SA.ts +3 -0
- package/locale/lang/en-US.ts +3 -0
- package/locale/lang/zh-CN.ts +3 -0
- package/package.json +97 -1
- package/tags.json +1 -1
- package/web-types.json +1 -1
- package/components/oxy-number-keyboard/index.scss +0 -78
- package/components/oxy-number-keyboard/key/index.scss +0 -81
- package/components/oxy-number-keyboard/key/index.vue +0 -78
- package/components/oxy-number-keyboard/key/types.ts +0 -11
- package/components/oxy-number-keyboard/oxy-number-keyboard.vue +0 -151
- package/components/oxy-number-keyboard/types.ts +0 -83
- package/components/oxy-tree/components/tree-node-content.vue +0 -72
- package/components/oxy-tree/index.ts +0 -51
- package/oxy-uni-ui.zip +0 -0
|
@@ -16,46 +16,199 @@ function s4() {
|
|
|
16
16
|
.substring(1)
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
type UnitConvertOutput = 'number' | 'px'
|
|
20
|
+
type DefaultUnit = 'px' | 'rpx'
|
|
21
|
+
|
|
19
22
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
+
* 通用单位转换函数。
|
|
24
|
+
*
|
|
25
|
+
* 支持输入:
|
|
26
|
+
* - `number`、纯数字字符串(如 `'12'`)
|
|
27
|
+
* - 带单位字符串:`px` / `rpx` / `%` / `em`
|
|
28
|
+
* - CSS 关键字(仅在 `output='px'` 且 `preserveCssKeyword=true` 时原样透传)
|
|
29
|
+
*
|
|
30
|
+
* 转换规则:
|
|
31
|
+
* - `output='number'`(默认):返回数值(px 语义)。
|
|
32
|
+
* - `rpx` -> `uni.upx2px`
|
|
33
|
+
* - `px` -> 原数值
|
|
34
|
+
* - `%` -> 按 `base` 计算
|
|
35
|
+
* - `output='px'`:返回可直接用于内联样式的字符串。
|
|
36
|
+
* - 数字/纯数字字符串 -> `${value}px`
|
|
37
|
+
* - 可识别单位按规则换算后输出 `${n}px`
|
|
38
|
+
* - 关键字(如 `auto`)按配置透传
|
|
39
|
+
*
|
|
40
|
+
* @param value 待转换的值。
|
|
41
|
+
* @param base 百分比计算基准,仅在输入为 `%` 时生效。
|
|
42
|
+
* @param options 转换配置:
|
|
43
|
+
* - `output`:`'number' | 'px'`
|
|
44
|
+
* - `preserveCssKeyword`:`output='px'` 时是否透传 CSS 关键字,默认 `true`
|
|
45
|
+
* @returns `output='number'` 时返回 `number`;`output='px'` 时返回 `string`。
|
|
46
|
+
*/
|
|
47
|
+
export function unitConvert<T extends UnitConvertOutput = 'number'>(
|
|
48
|
+
value: string | number | null | undefined,
|
|
49
|
+
base: number = 0,
|
|
50
|
+
options: { output?: T; preserveCssKeyword?: boolean } = {}
|
|
51
|
+
): T extends 'px' ? string : number {
|
|
52
|
+
const output = options.output ?? 'number'
|
|
53
|
+
const preserveCssKeyword = options.preserveCssKeyword ?? true
|
|
54
|
+
|
|
55
|
+
const toNumber = (input: string | number | null | undefined): number => {
|
|
56
|
+
// 如果是字符串数字
|
|
57
|
+
if (isNumeric(input)) {
|
|
58
|
+
return Number(input)
|
|
59
|
+
}
|
|
60
|
+
// 如果有单位
|
|
61
|
+
if (isString(input)) {
|
|
62
|
+
const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g
|
|
63
|
+
const results = reg.exec(input)
|
|
64
|
+
if (!input || !results) {
|
|
65
|
+
return 0
|
|
66
|
+
}
|
|
67
|
+
const unit = results[3]
|
|
68
|
+
const _value = parseFloat(input)
|
|
69
|
+
if (unit === 'rpx') {
|
|
70
|
+
return uni.upx2px(_value)
|
|
71
|
+
}
|
|
72
|
+
if (unit === 'px') {
|
|
73
|
+
return _value * 1
|
|
74
|
+
}
|
|
75
|
+
if (unit == '%') {
|
|
76
|
+
return (_value / 100) * base
|
|
77
|
+
}
|
|
78
|
+
// 如果是其他单位,可以继续添加对应的转换逻辑
|
|
79
|
+
}
|
|
80
|
+
return 0
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (output === 'px') {
|
|
84
|
+
if (value === null || value === undefined || value === '') {
|
|
85
|
+
return '0px' as T extends 'px' ? string : number
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (isNumber(value)) {
|
|
89
|
+
return `${value}px` as T extends 'px' ? string : number
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (isString(value)) {
|
|
93
|
+
const trimmed = value.trim()
|
|
94
|
+
|
|
95
|
+
if (!trimmed) {
|
|
96
|
+
return '0px' as T extends 'px' ? string : number
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (
|
|
100
|
+
preserveCssKeyword &&
|
|
101
|
+
(trimmed === 'auto' || trimmed === 'inherit' || trimmed === 'initial' || trimmed === 'unset' || trimmed.endsWith('%'))
|
|
102
|
+
) {
|
|
103
|
+
return trimmed as T extends 'px' ? string : number
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (isNumeric(trimmed)) {
|
|
107
|
+
return `${Number(trimmed)}px` as T extends 'px' ? string : number
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const convertedValue = toNumber(trimmed)
|
|
111
|
+
|
|
112
|
+
if (convertedValue || /^-?0(\.0+)?(rpx|px)?$/.test(trimmed)) {
|
|
113
|
+
return `${convertedValue}px` as T extends 'px' ? string : number
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return trimmed as T extends 'px' ? string : number
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return `${toNumber(value)}px` as T extends 'px' ? string : number
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return toNumber(value) as T extends 'px' ? string : number
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 为“无单位值”补充默认单位。
|
|
127
|
+
*
|
|
128
|
+
* 行为说明:
|
|
129
|
+
* - `number` -> `${value}${defaultUnit}`
|
|
130
|
+
* - 纯数字字符串 -> `${value}${defaultUnit}`
|
|
131
|
+
* - `null/undefined/''` -> `0${defaultUnit}`
|
|
132
|
+
* - 已带单位或其他字符串(如 `300rpx`、`20px`、`50%`、`auto`)原样返回
|
|
133
|
+
*
|
|
134
|
+
* 典型用途:
|
|
135
|
+
* - 统一“number 与纯数字字符串”的默认单位语义(如统一按 `rpx`)。
|
|
136
|
+
*
|
|
137
|
+
* @param value 输入值。
|
|
138
|
+
* @param defaultUnit 默认单位,支持 `'px' | 'rpx'`,默认 `'rpx'`。
|
|
139
|
+
* @returns 补全单位后的字符串结果。
|
|
140
|
+
*/
|
|
141
|
+
export function withDefaultUnit(value: number | string | null | undefined, defaultUnit: DefaultUnit = 'rpx') {
|
|
142
|
+
if (value === null || value === undefined) {
|
|
143
|
+
return `0${defaultUnit}`
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (isNumber(value)) {
|
|
147
|
+
return `${value}${defaultUnit}`
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const trimmed = value.trim()
|
|
151
|
+
|
|
152
|
+
if (!trimmed) {
|
|
153
|
+
return `0${defaultUnit}`
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (isNumeric(trimmed)) {
|
|
157
|
+
return `${trimmed}${defaultUnit}`
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return trimmed
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 先补默认单位,再执行 `unitConvert`,用于得到稳定的数值结果。
|
|
165
|
+
*
|
|
166
|
+
* 等价逻辑:
|
|
167
|
+
* `unitConvert(withDefaultUnit(value, defaultUnit), base)`
|
|
168
|
+
*
|
|
169
|
+
* 适用场景:
|
|
170
|
+
* - 需要做数值比较(如滚动阈值判断),同时希望 `number`/纯数字字符串有明确默认单位语义。
|
|
171
|
+
*
|
|
172
|
+
* @param value 输入值。
|
|
173
|
+
* @param options 配置项:
|
|
174
|
+
* - `defaultUnit`:无单位值补充的默认单位,默认 `'rpx'`
|
|
175
|
+
* - `base`:百分比换算基准,默认 `0`
|
|
176
|
+
* @returns 转换后的数值(px 语义)。
|
|
23
177
|
*/
|
|
24
|
-
export function
|
|
25
|
-
|
|
178
|
+
export function unitConvertWithDefault(value: number | string | null | undefined, options: { defaultUnit?: DefaultUnit; base?: number } = {}) {
|
|
179
|
+
const { defaultUnit = 'rpx', base = 0 } = options
|
|
180
|
+
return unitConvert(withDefaultUnit(value, defaultUnit), base)
|
|
26
181
|
}
|
|
27
182
|
|
|
28
183
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
184
|
+
* 将长度值解析为样式字符串,仅对 `%` 做屏宽换算。
|
|
185
|
+
*
|
|
186
|
+
* 行为说明:
|
|
187
|
+
* - `number`/纯数字字符串:按 `defaultUnit` 补单位(默认补 `rpx`)
|
|
188
|
+
* - `%`:按 `uni.getSystemInfoSync().windowWidth` 换算后转为 `px`
|
|
189
|
+
* - 其他带单位值(如 `px/rpx`):原样返回
|
|
190
|
+
*
|
|
191
|
+
* @param value 输入长度值。
|
|
192
|
+
* @param options 配置项:
|
|
193
|
+
* - `defaultUnit`:无单位值的默认单位,默认 `'rpx'`
|
|
194
|
+
* @returns 解析后的样式值字符串;当输入为空时返回空字符串。
|
|
32
195
|
*/
|
|
33
|
-
export function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return Number(value)
|
|
196
|
+
export function resolveSizeWithScreenWidth(value: number | string | null | undefined, options: { defaultUnit?: DefaultUnit } = {}) {
|
|
197
|
+
if (value === '' || value === undefined || value === null) {
|
|
198
|
+
return ''
|
|
37
199
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
if (unit === 'rpx') {
|
|
48
|
-
return uni.upx2px(_value)
|
|
49
|
-
}
|
|
50
|
-
if (unit === 'px') {
|
|
51
|
-
return _value * 1
|
|
52
|
-
}
|
|
53
|
-
if (unit == '%') {
|
|
54
|
-
return (_value / 100) * base
|
|
55
|
-
}
|
|
56
|
-
// 如果是其他单位,可以继续添加对应的转换逻辑
|
|
200
|
+
|
|
201
|
+
const { defaultUnit = 'rpx' } = options
|
|
202
|
+
const normalized = withDefaultUnit(value, defaultUnit)
|
|
203
|
+
const trimmed = normalized.trim()
|
|
204
|
+
|
|
205
|
+
if (trimmed.endsWith('%')) {
|
|
206
|
+
const { windowWidth = 0 } = uni.getSystemInfoSync()
|
|
207
|
+
const percentInPx = unitConvert(trimmed, windowWidth)
|
|
208
|
+
return `${percentInPx * 2}rpx`
|
|
57
209
|
}
|
|
58
|
-
|
|
210
|
+
|
|
211
|
+
return normalized
|
|
59
212
|
}
|
|
60
213
|
|
|
61
214
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getCurrentInstance, ref } from 'vue'
|
|
2
|
-
import { getRect, isObj } from '../common/util'
|
|
2
|
+
import { getRect, isObj, unitConvert } from '../common/util'
|
|
3
3
|
|
|
4
4
|
export function usePopover(visibleArrow = true) {
|
|
5
5
|
const { proxy } = getCurrentInstance() as any
|
|
@@ -14,6 +14,7 @@ export function usePopover(visibleArrow = true) {
|
|
|
14
14
|
const width = ref<number>(0)
|
|
15
15
|
const height = ref<number>(0)
|
|
16
16
|
const top = ref<number>(0)
|
|
17
|
+
const toPx = (value: number) => unitConvert(value, 0, { output: 'px' })
|
|
17
18
|
|
|
18
19
|
function noop() {}
|
|
19
20
|
|
|
@@ -107,64 +108,67 @@ export function usePopover(visibleArrow = true) {
|
|
|
107
108
|
|
|
108
109
|
const placements = new Map([
|
|
109
110
|
// 上
|
|
110
|
-
['top', [`left: ${verticalX}
|
|
111
|
+
['top', [`left: ${toPx(verticalX)}; bottom: ${toPx(verticalY)}; transform: translateX(-50%);`, 'left: 50%;']],
|
|
111
112
|
[
|
|
112
113
|
'top-start',
|
|
113
114
|
[
|
|
114
|
-
`left: ${offsetX}
|
|
115
|
-
`left: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}
|
|
115
|
+
`left: ${toPx(offsetX)}; bottom: ${toPx(verticalY)};`,
|
|
116
|
+
`left: ${toPx((popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX)};`
|
|
116
117
|
]
|
|
117
118
|
],
|
|
118
119
|
[
|
|
119
120
|
'top-end',
|
|
120
121
|
[
|
|
121
|
-
`right: ${offsetX}
|
|
122
|
-
`right: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}
|
|
122
|
+
`right: ${toPx(offsetX)}; bottom: ${toPx(verticalY)};`,
|
|
123
|
+
`right: ${toPx((popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX)}; transform: translateX(50%);`
|
|
123
124
|
]
|
|
124
125
|
],
|
|
125
126
|
// 下
|
|
126
|
-
['bottom', [`left: ${verticalX}
|
|
127
|
+
['bottom', [`left: ${toPx(verticalX)}; top: ${toPx(verticalY)}; transform: translateX(-50%);`, 'left: 50%;']],
|
|
127
128
|
[
|
|
128
129
|
'bottom-start',
|
|
129
|
-
[
|
|
130
|
+
[
|
|
131
|
+
`left: ${toPx(offsetX)}; top: ${toPx(verticalY)};`,
|
|
132
|
+
`left: ${toPx((popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX)};`
|
|
133
|
+
]
|
|
130
134
|
],
|
|
131
135
|
[
|
|
132
136
|
'bottom-end',
|
|
133
137
|
[
|
|
134
|
-
`right: ${offsetX}
|
|
135
|
-
`right: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}
|
|
138
|
+
`right: ${toPx(offsetX)}; top: ${toPx(verticalY)};`,
|
|
139
|
+
`right: ${toPx((popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX)}; transform: translateX(50%);`
|
|
136
140
|
]
|
|
137
141
|
],
|
|
138
142
|
// 左
|
|
139
|
-
['left', [`right: ${horizontalX}
|
|
143
|
+
['left', [`right: ${toPx(horizontalX)}; top: ${toPx(horizontalY)}; transform: translateY(-50%);`, 'top: 50%']],
|
|
140
144
|
[
|
|
141
145
|
'left-start',
|
|
142
146
|
[
|
|
143
|
-
`right: ${horizontalX}
|
|
144
|
-
`top: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}
|
|
147
|
+
`right: ${toPx(horizontalX)}; top: ${toPx(offsetY)};`,
|
|
148
|
+
`top: ${toPx((popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY)};`
|
|
145
149
|
]
|
|
146
150
|
],
|
|
147
151
|
[
|
|
148
152
|
'left-end',
|
|
149
153
|
[
|
|
150
|
-
`right: ${horizontalX}
|
|
151
|
-
`bottom: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}
|
|
154
|
+
`right: ${toPx(horizontalX)}; bottom: ${toPx(offsetY)};`,
|
|
155
|
+
`bottom: ${toPx((popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY)}; transform: translateY(50%);`
|
|
152
156
|
]
|
|
153
157
|
],
|
|
154
158
|
// 右
|
|
155
|
-
['right', [`left: ${horizontalX}
|
|
159
|
+
['right', [`left: ${toPx(horizontalX)}; top: ${toPx(horizontalY)}; transform: translateY(-50%);`, 'top: 50%']],
|
|
156
160
|
[
|
|
157
161
|
'right-start',
|
|
158
162
|
[
|
|
159
|
-
`left: ${horizontalX}
|
|
160
|
-
`top: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}
|
|
163
|
+
`left: ${toPx(horizontalX)}; top: ${toPx(offsetY)};`,
|
|
164
|
+
`top: ${toPx((popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY)};`
|
|
161
165
|
]
|
|
162
166
|
],
|
|
163
167
|
[
|
|
164
168
|
'right-end',
|
|
165
169
|
[
|
|
166
|
-
`left: ${horizontalX}
|
|
167
|
-
`bottom: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}
|
|
170
|
+
`left: ${toPx(horizontalX)}; bottom: ${toPx(offsetY)};`,
|
|
171
|
+
`bottom: ${toPx((popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY)}; transform: translateY(50%);`
|
|
168
172
|
]
|
|
169
173
|
]
|
|
170
174
|
])
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { ref, computed, watch, nextTick, type Ref } from 'vue'
|
|
6
6
|
import { VirtualScrollEngine } from '../oxy-virtual-scroll/virtual-scroll'
|
|
7
|
+
import { unitConvert, unitConvertWithDefault } from '../common/util'
|
|
7
8
|
|
|
8
9
|
export interface UseVirtualScrollOptions {
|
|
9
10
|
data: Ref<any[]>
|
|
@@ -52,7 +53,10 @@ export function useVirtualScroll(options: UseVirtualScrollOptions): UseVirtualSc
|
|
|
52
53
|
const displayData = computed<any[]>(() => data.value)
|
|
53
54
|
|
|
54
55
|
const totalHeight = computed(() => {
|
|
55
|
-
return displayData.value.length *
|
|
56
|
+
return displayData.value.length * unitConvertWithDefault(itemHeight.value, { defaultUnit: 'rpx' })
|
|
57
|
+
})
|
|
58
|
+
const backToTopThresholdInPx = computed(() => {
|
|
59
|
+
return unitConvertWithDefault(backToTopThreshold.value, { defaultUnit: 'rpx' })
|
|
56
60
|
})
|
|
57
61
|
|
|
58
62
|
// 监听数据变化
|
|
@@ -72,13 +76,14 @@ export function useVirtualScroll(options: UseVirtualScrollOptions): UseVirtualSc
|
|
|
72
76
|
if (!virtual.value) {
|
|
73
77
|
// 非虚拟滚动模式:直接使用全部数据
|
|
74
78
|
virtualData.value = displayData.value
|
|
79
|
+
startIndex.value = 0
|
|
75
80
|
virtualOffsetY.value = 0
|
|
76
81
|
return
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
virtualEngine.value = new VirtualScrollEngine({
|
|
80
|
-
containerHeight:
|
|
81
|
-
itemHeight:
|
|
85
|
+
containerHeight: unitConvert(height.value),
|
|
86
|
+
itemHeight: unitConvertWithDefault(itemHeight.value, { defaultUnit: 'rpx' }),
|
|
82
87
|
data: displayData.value
|
|
83
88
|
})
|
|
84
89
|
updateVisibleData()
|
|
@@ -89,8 +94,8 @@ export function useVirtualScroll(options: UseVirtualScrollOptions): UseVirtualSc
|
|
|
89
94
|
if (!virtual.value) return
|
|
90
95
|
|
|
91
96
|
virtualEngine.value = new VirtualScrollEngine({
|
|
92
|
-
containerHeight:
|
|
93
|
-
itemHeight:
|
|
97
|
+
containerHeight: unitConvert(height.value),
|
|
98
|
+
itemHeight: unitConvertWithDefault(itemHeight.value, { defaultUnit: 'rpx' }),
|
|
94
99
|
data: displayData.value
|
|
95
100
|
})
|
|
96
101
|
}
|
|
@@ -100,52 +105,74 @@ export function useVirtualScroll(options: UseVirtualScrollOptions): UseVirtualSc
|
|
|
100
105
|
if (!virtual.value) return // 非虚拟模式不处理
|
|
101
106
|
|
|
102
107
|
if (virtualEngine.value) {
|
|
103
|
-
const { visibleData, offsetY } = virtualEngine.value.updateVisibleData(_scrollTop.value || 0)
|
|
108
|
+
const { visibleData, offsetY, startIndex: engineStartIndex } = virtualEngine.value.updateVisibleData(_scrollTop.value || 0)
|
|
104
109
|
virtualData.value = visibleData
|
|
110
|
+
startIndex.value = engineStartIndex
|
|
105
111
|
virtualOffsetY.value = offsetY
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
114
|
|
|
115
|
+
function syncProgrammaticScrollState(scrollTopValue: number) {
|
|
116
|
+
_scrollTop.value = scrollTopValue
|
|
117
|
+
showBackTopBtn.value = scrollTopValue > backToTopThresholdInPx.value
|
|
118
|
+
updateVisibleData()
|
|
119
|
+
}
|
|
120
|
+
|
|
109
121
|
// 滚动事件处理
|
|
110
122
|
function onScroll(scrollTopValue: number) {
|
|
111
123
|
_scrollTop.value = scrollTopValue
|
|
112
|
-
showBackTopBtn.value = scrollTopValue >
|
|
124
|
+
showBackTopBtn.value = scrollTopValue > backToTopThresholdInPx.value
|
|
113
125
|
updateVisibleData()
|
|
114
126
|
}
|
|
115
127
|
|
|
116
128
|
// 滚动到顶部
|
|
117
129
|
function scrollToTop() {
|
|
118
|
-
|
|
119
|
-
nextTick(() => {
|
|
120
|
-
scrollTop.value = 0
|
|
121
|
-
})
|
|
130
|
+
scrollToPosition('0px')
|
|
122
131
|
}
|
|
123
132
|
|
|
124
133
|
// 滚动到底部
|
|
125
134
|
function scrollToBottom() {
|
|
126
|
-
scrollToPosition(totalHeight.value)
|
|
135
|
+
scrollToPosition(`${totalHeight.value}px`)
|
|
127
136
|
}
|
|
128
137
|
|
|
129
138
|
// 滚动到指定位置
|
|
130
139
|
function scrollToPosition(position: number | string) {
|
|
131
|
-
|
|
140
|
+
const targetScrollTop = unitConvertWithDefault(position, { defaultUnit: 'rpx' })
|
|
141
|
+
|
|
142
|
+
// scroll-view 在绑定值重复时可能不触发滚动,先同步当前真实滚动值再设置目标值
|
|
143
|
+
if (scrollTop.value === targetScrollTop) {
|
|
144
|
+
scrollTop.value = _scrollTop.value
|
|
145
|
+
nextTick(() => {
|
|
146
|
+
scrollTop.value = targetScrollTop
|
|
147
|
+
syncProgrammaticScrollState(targetScrollTop)
|
|
148
|
+
})
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
scrollTop.value = targetScrollTop
|
|
153
|
+
syncProgrammaticScrollState(targetScrollTop)
|
|
132
154
|
}
|
|
133
155
|
|
|
134
156
|
// 滚动到指定元素
|
|
135
157
|
function scrollToElement(item: any) {
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
158
|
+
const targetId = item?.[idKey.value]
|
|
159
|
+
if (targetId === undefined || targetId === null) return
|
|
160
|
+
|
|
161
|
+
const index = data.value.findIndex((o) => o?.[idKey.value] === targetId)
|
|
162
|
+
if (index >= 0) {
|
|
163
|
+
const scrollDistance = unitConvertWithDefault(itemHeight.value, { defaultUnit: 'rpx' }) * index
|
|
164
|
+
scrollToPosition(`${scrollDistance}px`)
|
|
140
165
|
}
|
|
141
166
|
}
|
|
142
167
|
|
|
143
168
|
// 根据ID滚动到指定元素
|
|
144
169
|
function scrollToElementById(id: string | number) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
170
|
+
if (id === undefined || id === null) return
|
|
171
|
+
|
|
172
|
+
const index = data.value.findIndex((o) => o?.[idKey.value] === id)
|
|
173
|
+
if (index >= 0) {
|
|
174
|
+
const scrollDistance = unitConvertWithDefault(itemHeight.value, { defaultUnit: 'rpx' }) * index
|
|
175
|
+
scrollToPosition(`${scrollDistance}px`)
|
|
149
176
|
}
|
|
150
177
|
}
|
|
151
178
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { onBeforeUnmount, onMounted } from 'vue'
|
|
2
|
+
|
|
3
|
+
export interface WindowResizeResult {
|
|
4
|
+
size?: {
|
|
5
|
+
windowWidth?: number
|
|
6
|
+
windowHeight?: number
|
|
7
|
+
}
|
|
8
|
+
windowWidth?: number
|
|
9
|
+
windowHeight?: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type WindowResizeCallback = (result?: WindowResizeResult) => void | Promise<void>
|
|
13
|
+
|
|
14
|
+
interface UseWindowResizeOptions {
|
|
15
|
+
immediate?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function useWindowResize(callback: WindowResizeCallback, options: UseWindowResizeOptions = {}) {
|
|
19
|
+
const { immediate = false } = options
|
|
20
|
+
|
|
21
|
+
onMounted(() => {
|
|
22
|
+
if (immediate) {
|
|
23
|
+
callback()
|
|
24
|
+
}
|
|
25
|
+
if (typeof uni.onWindowResize === 'function') {
|
|
26
|
+
uni.onWindowResize(callback)
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
onBeforeUnmount(() => {
|
|
31
|
+
if (typeof uni.offWindowResize === 'function') {
|
|
32
|
+
uni.offWindowResize(callback)
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
}
|
|
@@ -50,16 +50,29 @@
|
|
|
50
50
|
border-radius: $-action-sheet-radius $-action-sheet-radius 0 0;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
:deep(.oxy-action-sheet__popup--float) {
|
|
54
|
+
border-radius: 0 !important;
|
|
55
|
+
background: transparent !important;
|
|
56
|
+
overflow: visible !important;
|
|
57
|
+
}
|
|
58
|
+
|
|
53
59
|
@include b(action-sheet) {
|
|
54
60
|
background-color: $-color-white;
|
|
55
|
-
padding-bottom:
|
|
61
|
+
padding-bottom: 2rpx;
|
|
62
|
+
margin-bottom: var(--window-bottom);
|
|
63
|
+
|
|
64
|
+
@include when(float) {
|
|
65
|
+
margin: 0 20rpx calc(var(--window-bottom) + 20rpx);
|
|
66
|
+
border-radius: $-action-sheet-radius;
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
}
|
|
56
69
|
|
|
57
70
|
@include edeep(popup) {
|
|
58
71
|
border-radius: $-action-sheet-radius $-action-sheet-radius 0 0;
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
@include e(actions) {
|
|
62
|
-
padding:
|
|
75
|
+
padding: 20rpx 0;
|
|
63
76
|
max-height: 50vh;
|
|
64
77
|
overflow-y: auto;
|
|
65
78
|
-webkit-overflow-scrolling: touch;
|
|
@@ -110,14 +123,14 @@
|
|
|
110
123
|
|
|
111
124
|
@include e(subname) {
|
|
112
125
|
display: inline-block;
|
|
113
|
-
margin-left:
|
|
126
|
+
margin-left: 12rpx;
|
|
114
127
|
font-size: $-action-sheet-subname-fs;
|
|
115
128
|
color: $-action-sheet-subname-color;
|
|
116
129
|
}
|
|
117
130
|
|
|
118
131
|
@include e(cancel) {
|
|
119
132
|
display: block;
|
|
120
|
-
width: calc(100% -
|
|
133
|
+
width: calc(100% - 96rpx);
|
|
121
134
|
line-height: $-action-sheet-cancel-height;
|
|
122
135
|
padding: 0;
|
|
123
136
|
color: $-action-sheet-cancel-color;
|
|
@@ -127,7 +140,7 @@
|
|
|
127
140
|
border: none;
|
|
128
141
|
background: $-action-sheet-cancel-bg;
|
|
129
142
|
outline: none;
|
|
130
|
-
margin: 0 auto
|
|
143
|
+
margin: 0 auto 48rpx;
|
|
131
144
|
font-weight: $-action-sheet-weight;
|
|
132
145
|
|
|
133
146
|
&:active {
|
|
@@ -160,15 +173,15 @@
|
|
|
160
173
|
}
|
|
161
174
|
|
|
162
175
|
@include e(panels) {
|
|
163
|
-
height:
|
|
176
|
+
height: 168rpx;
|
|
164
177
|
overflow-y: hidden;
|
|
165
178
|
|
|
166
179
|
&:first-of-type {
|
|
167
|
-
margin-top:
|
|
180
|
+
margin-top: 40rpx;
|
|
168
181
|
}
|
|
169
182
|
|
|
170
183
|
&:last-of-type {
|
|
171
|
-
margin-bottom:
|
|
184
|
+
margin-bottom: 24rpx;
|
|
172
185
|
}
|
|
173
186
|
}
|
|
174
187
|
|
|
@@ -179,7 +192,7 @@
|
|
|
179
192
|
}
|
|
180
193
|
|
|
181
194
|
@include e(panel) {
|
|
182
|
-
width:
|
|
195
|
+
width: 176rpx;
|
|
183
196
|
flex: 0 0 auto;
|
|
184
197
|
display: inline-block;
|
|
185
198
|
padding: $-action-sheet-panel-padding;
|
|
@@ -190,7 +203,7 @@
|
|
|
190
203
|
width: $-action-sheet-panel-img-fs;
|
|
191
204
|
height: $-action-sheet-panel-img-fs;
|
|
192
205
|
margin: 0 auto;
|
|
193
|
-
margin-bottom:
|
|
206
|
+
margin-bottom: 16rpx;
|
|
194
207
|
border-radius: $-action-sheet-panel-img-radius;
|
|
195
208
|
}
|
|
196
209
|
|
|
@@ -201,4 +214,4 @@
|
|
|
201
214
|
color: $-action-sheet-color;
|
|
202
215
|
@include lineEllipsis;
|
|
203
216
|
}
|
|
204
|
-
}
|
|
217
|
+
}
|