tang-ui-x 1.0.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/LICENSE +21 -0
- package/README.md +141 -0
- package/components/TActionSheet/index.uvue +170 -0
- package/components/TActionSheet/type.uts +29 -0
- package/components/TAvatar/index.uvue +156 -0
- package/components/TAvatar/type.uts +54 -0
- package/components/TBadge/index.uvue +152 -0
- package/components/TBadge/type.uts +48 -0
- package/components/TButton/README.md +111 -0
- package/components/TButton/index.uvue +380 -0
- package/components/TButton/type.uts +95 -0
- package/components/TCard/index.uvue +174 -0
- package/components/TCard/type.uts +50 -0
- package/components/TCell/index.uvue +49 -0
- package/components/TCheckbox/index.uvue +187 -0
- package/components/TCheckboxGroup/index.uvue +139 -0
- package/components/TCheckboxGroup/type.uts +26 -0
- package/components/TCol/index.uvue +82 -0
- package/components/TCol/type.uts +30 -0
- package/components/TCollapse/index.uvue +93 -0
- package/components/TCollapse/type.uts +36 -0
- package/components/TCollapseItem/index.uvue +194 -0
- package/components/TCollapseItem/type.uts +25 -0
- package/components/TDialog/index.uvue +386 -0
- package/components/TDialog/type.uts +84 -0
- package/components/TDivider/index.uvue +235 -0
- package/components/TDivider/type.uts +91 -0
- package/components/TEmpty/index.uvue +128 -0
- package/components/TErrorState/index.uvue +57 -0
- package/components/TGrid/index.uvue +115 -0
- package/components/TGrid/type.uts +77 -0
- package/components/TGridItem/index.uvue +243 -0
- package/components/TGridItem/type.uts +64 -0
- package/components/TIcon/index.uvue +96 -0
- package/components/TImage/index.uvue +255 -0
- package/components/TImage/type.uts +146 -0
- package/components/TInput/README.md +119 -0
- package/components/TInput/index.uvue +376 -0
- package/components/TInput/type.uts +138 -0
- package/components/TList/index.uvue +82 -0
- package/components/TList/type.uts +68 -0
- package/components/TListItem/index.uvue +161 -0
- package/components/TListItem/type.uts +49 -0
- package/components/TLoading/index.uvue +153 -0
- package/components/TLoading/type.uts +43 -0
- package/components/TNavBar/index.uvue +120 -0
- package/components/TNavBar/type.uts +22 -0
- package/components/TNoticeBar/index.uvue +106 -0
- package/components/TNoticeBar/type.uts +21 -0
- package/components/TNumberInput/index.uvue +226 -0
- package/components/TPicker/index.uvue +276 -0
- package/components/TPicker/type.uts +105 -0
- package/components/TPopup/index.uvue +442 -0
- package/components/TProgress/index.uvue +103 -0
- package/components/TProgress/type.uts +64 -0
- package/components/TRadioButton/index.uvue +232 -0
- package/components/TRadioGroup/index.uvue +117 -0
- package/components/TRadioGroup/type.uts +25 -0
- package/components/TRate/index.uvue +182 -0
- package/components/TRow/index.uvue +105 -0
- package/components/TRow/type.uts +52 -0
- package/components/TSearchBar/index.uvue +255 -0
- package/components/TSearchBar/type.uts +140 -0
- package/components/TSelect/index.uvue +655 -0
- package/components/TSelect/type.uts +57 -0
- package/components/TSlider/index.uvue +72 -0
- package/components/TSlider/type.uts +21 -0
- package/components/TSwiper/index.uvue +222 -0
- package/components/TSwiper/type.uts +77 -0
- package/components/TSwitch/index.uvue +177 -0
- package/components/TSwitch/type.uts +52 -0
- package/components/TText/README.md +124 -0
- package/components/TText/index.uvue +257 -0
- package/components/TText/type.uts +114 -0
- package/components/TTextarea/index.uvue +239 -0
- package/components/TTextarea/type.uts +106 -0
- package/components/TToast/type.uts +14 -0
- package/components/Tabs/README.md +297 -0
- package/components/Tabs/index.uvue +383 -0
- package/components/Tabs/type.uts +10 -0
- package/components/Tags/README.md +297 -0
- package/components/Tags/index.uvue +383 -0
- package/components/Tags/type.uts +10 -0
- package/components/VbenFrom/index.uvue +392 -0
- package/composables/useModal.uts +294 -0
- package/composables/useTheme.uts +235 -0
- package/composables/useToast.uts +322 -0
- package/index.js +62 -0
- package/package.json +48 -0
- package/style/colors/index.scss +157 -0
- package/style/index.scss +399 -0
- package/types/index.uts +52 -0
- package/uni.scss +79 -0
- package/utils/color.uts +92 -0
- package/utils/common.uts +245 -0
- package/utils/dom.uts +275 -0
- package/utils/index.uts +10 -0
- package/utils/validator.uts +155 -0
package/utils/color.uts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 颜色处理工具函数
|
|
3
|
+
* @description 提供颜色转换、处理等功能
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 十六进制颜色转 RGB
|
|
8
|
+
* @param hex 十六进制颜色值,如 #ffffff
|
|
9
|
+
* @returns RGB 对象 { r, g, b }
|
|
10
|
+
*/
|
|
11
|
+
export function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
|
|
12
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
|
|
13
|
+
return result
|
|
14
|
+
? {
|
|
15
|
+
r: parseInt(result[1], 16),
|
|
16
|
+
g: parseInt(result[2], 16),
|
|
17
|
+
b: parseInt(result[3], 16)
|
|
18
|
+
}
|
|
19
|
+
: null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* RGB 转十六进制颜色
|
|
24
|
+
* @param r 红色值 0-255
|
|
25
|
+
* @param g 绿色值 0-255
|
|
26
|
+
* @param b 蓝色值 0-255
|
|
27
|
+
* @returns 十六进制颜色值
|
|
28
|
+
*/
|
|
29
|
+
export function rgbToHex(r: number, g: number, b: number): string {
|
|
30
|
+
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 颜色加深
|
|
35
|
+
* @param color 颜色值
|
|
36
|
+
* @param amount 加深程度 0-1
|
|
37
|
+
* @returns 加深后的颜色
|
|
38
|
+
*/
|
|
39
|
+
export function darken(color: string, amount: number): string {
|
|
40
|
+
const rgb = hexToRgb(color)
|
|
41
|
+
if (!rgb) return color
|
|
42
|
+
|
|
43
|
+
const r = Math.max(0, Math.floor(rgb.r * (1 - amount)))
|
|
44
|
+
const g = Math.max(0, Math.floor(rgb.g * (1 - amount)))
|
|
45
|
+
const b = Math.max(0, Math.floor(rgb.b * (1 - amount)))
|
|
46
|
+
|
|
47
|
+
return rgbToHex(r, g, b)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 颜色变浅
|
|
52
|
+
* @param color 颜色值
|
|
53
|
+
* @param amount 变浅程度 0-1
|
|
54
|
+
* @returns 变浅后的颜色
|
|
55
|
+
*/
|
|
56
|
+
export function lighten(color: string, amount: number): string {
|
|
57
|
+
const rgb = hexToRgb(color)
|
|
58
|
+
if (!rgb) return color
|
|
59
|
+
|
|
60
|
+
const r = Math.min(255, Math.floor(rgb.r + (255 - rgb.r) * amount))
|
|
61
|
+
const g = Math.min(255, Math.floor(rgb.g + (255 - rgb.g) * amount))
|
|
62
|
+
const b = Math.min(255, Math.floor(rgb.b + (255 - rgb.b) * amount))
|
|
63
|
+
|
|
64
|
+
return rgbToHex(r, g, b)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 添加透明度
|
|
69
|
+
* @param color 颜色值
|
|
70
|
+
* @param opacity 透明度 0-1
|
|
71
|
+
* @returns rgba 颜色值
|
|
72
|
+
*/
|
|
73
|
+
export function addOpacity(color: string, opacity: number): string {
|
|
74
|
+
const rgb = hexToRgb(color)
|
|
75
|
+
if (!rgb) return color
|
|
76
|
+
|
|
77
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${opacity})`
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 判断颜色是否为浅色
|
|
82
|
+
* @param color 颜色值
|
|
83
|
+
* @returns 是否为浅色
|
|
84
|
+
*/
|
|
85
|
+
export function isLightColor(color: string): boolean {
|
|
86
|
+
const rgb = hexToRgb(color)
|
|
87
|
+
if (!rgb) return false
|
|
88
|
+
|
|
89
|
+
// 使用 YIQ 公式计算亮度
|
|
90
|
+
const yiq = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000
|
|
91
|
+
return yiq >= 128
|
|
92
|
+
}
|
package/utils/common.uts
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 通用工具函数
|
|
3
|
+
* @description 提供常用的工具函数
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 防抖函数
|
|
8
|
+
* @param func 要执行的函数
|
|
9
|
+
* @param wait 等待时间(毫秒)
|
|
10
|
+
* @returns 防抖后的函数
|
|
11
|
+
*/
|
|
12
|
+
export function debounce<T extends (...args: any[]) => any>(
|
|
13
|
+
func: T,
|
|
14
|
+
wait: number
|
|
15
|
+
): (...args: Parameters<T>) => void {
|
|
16
|
+
let timeout: number | null = null
|
|
17
|
+
|
|
18
|
+
return function (this: any, ...args: Parameters<T>) {
|
|
19
|
+
const context = this
|
|
20
|
+
|
|
21
|
+
if (timeout !== null) {
|
|
22
|
+
clearTimeout(timeout)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
timeout = setTimeout(() => {
|
|
26
|
+
func.apply(context, args)
|
|
27
|
+
}, wait)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 节流函数
|
|
33
|
+
* @param func 要执行的函数
|
|
34
|
+
* @param wait 等待时间(毫秒)
|
|
35
|
+
* @returns 节流后的函数
|
|
36
|
+
*/
|
|
37
|
+
export function throttle<T extends (...args: any[]) => any>(
|
|
38
|
+
func: T,
|
|
39
|
+
wait: number
|
|
40
|
+
): (...args: Parameters<T>) => void {
|
|
41
|
+
let timeout: number | null = null
|
|
42
|
+
let previous = 0
|
|
43
|
+
|
|
44
|
+
return function (this: any, ...args: Parameters<T>) {
|
|
45
|
+
const context = this
|
|
46
|
+
const now = Date.now()
|
|
47
|
+
|
|
48
|
+
if (now - previous > wait) {
|
|
49
|
+
if (timeout !== null) {
|
|
50
|
+
clearTimeout(timeout)
|
|
51
|
+
timeout = null
|
|
52
|
+
}
|
|
53
|
+
func.apply(context, args)
|
|
54
|
+
previous = now
|
|
55
|
+
} else if (!timeout) {
|
|
56
|
+
timeout = setTimeout(() => {
|
|
57
|
+
func.apply(context, args)
|
|
58
|
+
previous = Date.now()
|
|
59
|
+
timeout = null
|
|
60
|
+
}, wait)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 深拷贝
|
|
67
|
+
* @param obj 要拷贝的对象
|
|
68
|
+
* @returns 拷贝后的对象
|
|
69
|
+
*/
|
|
70
|
+
export function deepClone<T>(obj: T): T {
|
|
71
|
+
if (obj === null || typeof obj !== 'object') {
|
|
72
|
+
return obj
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (obj instanceof Date) {
|
|
76
|
+
return new Date(obj.getTime()) as any
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (obj instanceof Array) {
|
|
80
|
+
const cloneArr: any[] = []
|
|
81
|
+
obj.forEach((item) => {
|
|
82
|
+
cloneArr.push(deepClone(item))
|
|
83
|
+
})
|
|
84
|
+
return cloneArr as any
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (obj instanceof Object) {
|
|
88
|
+
const cloneObj: any = {}
|
|
89
|
+
for (const key in obj) {
|
|
90
|
+
if (obj.hasOwnProperty(key)) {
|
|
91
|
+
cloneObj[key] = deepClone(obj[key])
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return cloneObj
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return obj
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 生成唯一 ID
|
|
102
|
+
* @param prefix 前缀
|
|
103
|
+
* @returns 唯一 ID
|
|
104
|
+
*/
|
|
105
|
+
export function generateId(prefix: string = 'id'): string {
|
|
106
|
+
return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 格式化文件大小
|
|
111
|
+
* @param bytes 字节数
|
|
112
|
+
* @param decimals 小数位数
|
|
113
|
+
* @returns 格式化后的文件大小
|
|
114
|
+
*/
|
|
115
|
+
export function formatFileSize(bytes: number, decimals: number = 2): string {
|
|
116
|
+
if (bytes === 0) return '0 Bytes'
|
|
117
|
+
|
|
118
|
+
const k = 1024
|
|
119
|
+
const dm = decimals < 0 ? 0 : decimals
|
|
120
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
|
121
|
+
|
|
122
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
123
|
+
|
|
124
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 格式化日期
|
|
129
|
+
* @param date 日期对象或时间戳
|
|
130
|
+
* @param format 格式化模板,如 'YYYY-MM-DD HH:mm:ss'
|
|
131
|
+
* @returns 格式化后的日期字符串
|
|
132
|
+
*/
|
|
133
|
+
export function formatDate(date: Date | number, format: string = 'YYYY-MM-DD HH:mm:ss'): string {
|
|
134
|
+
const d = typeof date === 'number' ? new Date(date) : date
|
|
135
|
+
|
|
136
|
+
const year = d.getFullYear()
|
|
137
|
+
const month = d.getMonth() + 1
|
|
138
|
+
const day = d.getDate()
|
|
139
|
+
const hour = d.getHours()
|
|
140
|
+
const minute = d.getMinutes()
|
|
141
|
+
const second = d.getSeconds()
|
|
142
|
+
|
|
143
|
+
const pad = (n: number): string => (n < 10 ? '0' + n : String(n))
|
|
144
|
+
|
|
145
|
+
return format
|
|
146
|
+
.replace('YYYY', String(year))
|
|
147
|
+
.replace('MM', pad(month))
|
|
148
|
+
.replace('DD', pad(day))
|
|
149
|
+
.replace('HH', pad(hour))
|
|
150
|
+
.replace('mm', pad(minute))
|
|
151
|
+
.replace('ss', pad(second))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 获取 URL 参数
|
|
156
|
+
* @param url URL 地址
|
|
157
|
+
* @returns 参数对象
|
|
158
|
+
*/
|
|
159
|
+
export function getUrlParams(url: string): Record<string, string> {
|
|
160
|
+
const params: Record<string, string> = {}
|
|
161
|
+
const queryString = url.split('?')[1]
|
|
162
|
+
|
|
163
|
+
if (!queryString) return params
|
|
164
|
+
|
|
165
|
+
const pairs = queryString.split('&')
|
|
166
|
+
pairs.forEach((pair) => {
|
|
167
|
+
const [key, value] = pair.split('=')
|
|
168
|
+
params[decodeURIComponent(key)] = decodeURIComponent(value || '')
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
return params
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 对象转 URL 参数
|
|
176
|
+
* @param obj 参数对象
|
|
177
|
+
* @returns URL 参数字符串
|
|
178
|
+
*/
|
|
179
|
+
export function objectToUrlParams(obj: Record<string, any>): string {
|
|
180
|
+
const params: string[] = []
|
|
181
|
+
|
|
182
|
+
for (const key in obj) {
|
|
183
|
+
if (obj.hasOwnProperty(key) && obj[key] !== undefined && obj[key] !== null) {
|
|
184
|
+
params.push(`${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return params.join('&')
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 数组去重
|
|
193
|
+
* @param arr 数组
|
|
194
|
+
* @returns 去重后的数组
|
|
195
|
+
*/
|
|
196
|
+
export function unique<T>(arr: T[]): T[] {
|
|
197
|
+
return Array.from(new Set(arr))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* 数组分组
|
|
202
|
+
* @param arr 数组
|
|
203
|
+
* @param size 每组大小
|
|
204
|
+
* @returns 分组后的二维数组
|
|
205
|
+
*/
|
|
206
|
+
export function chunk<T>(arr: T[], size: number): T[][] {
|
|
207
|
+
const result: T[][] = []
|
|
208
|
+
for (let i = 0; i < arr.length; i += size) {
|
|
209
|
+
result.push(arr.slice(i, i + size))
|
|
210
|
+
}
|
|
211
|
+
return result
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 延迟执行
|
|
216
|
+
* @param ms 延迟时间(毫秒)
|
|
217
|
+
* @returns Promise
|
|
218
|
+
*/
|
|
219
|
+
export function sleep(ms: number): Promise<void> {
|
|
220
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* 随机数
|
|
225
|
+
* @param min 最小值
|
|
226
|
+
* @param max 最大值
|
|
227
|
+
* @returns 随机数
|
|
228
|
+
*/
|
|
229
|
+
export function random(min: number, max: number): number {
|
|
230
|
+
return Math.floor(Math.random() * (max - min + 1)) + min
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* 随机字符串
|
|
235
|
+
* @param length 长度
|
|
236
|
+
* @returns 随机字符串
|
|
237
|
+
*/
|
|
238
|
+
export function randomString(length: number): string {
|
|
239
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
240
|
+
let result = ''
|
|
241
|
+
for (let i = 0; i < length; i++) {
|
|
242
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length))
|
|
243
|
+
}
|
|
244
|
+
return result
|
|
245
|
+
}
|
package/utils/dom.uts
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM 操作工具函数
|
|
3
|
+
* @module utils/dom
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 获取元素的边界信息
|
|
8
|
+
* @param {string} selector - 选择器
|
|
9
|
+
* @param {any} instance - 组件实例
|
|
10
|
+
* @returns {Promise<any>} 元素边界信息
|
|
11
|
+
*/
|
|
12
|
+
export function getRect(selector: string, instance: any): Promise<any> {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
uni.createSelectorQuery()
|
|
15
|
+
.in(instance)
|
|
16
|
+
.select(selector)
|
|
17
|
+
.boundingClientRect((rect: any) => {
|
|
18
|
+
resolve(rect)
|
|
19
|
+
})
|
|
20
|
+
.exec()
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 获取所有匹配元素的边界信息
|
|
26
|
+
* @param {string} selector - 选择器
|
|
27
|
+
* @param {any} instance - 组件实例
|
|
28
|
+
* @returns {Promise<any[]>} 元素边界信息数组
|
|
29
|
+
*/
|
|
30
|
+
export function getRectAll(selector: string, instance: any): Promise<any[]> {
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
uni.createSelectorQuery()
|
|
33
|
+
.in(instance)
|
|
34
|
+
.selectAll(selector)
|
|
35
|
+
.boundingClientRect((rects: any[]) => {
|
|
36
|
+
resolve(rects)
|
|
37
|
+
})
|
|
38
|
+
.exec()
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 获取滚动位置
|
|
44
|
+
* @param {string} selector - 选择器
|
|
45
|
+
* @param {any} instance - 组件实例
|
|
46
|
+
* @returns {Promise<any>} 滚动位置信息
|
|
47
|
+
*/
|
|
48
|
+
export function getScrollOffset(selector: string, instance: any): Promise<any> {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
uni.createSelectorQuery()
|
|
51
|
+
.in(instance)
|
|
52
|
+
.select(selector)
|
|
53
|
+
.scrollOffset((res: any) => {
|
|
54
|
+
resolve(res)
|
|
55
|
+
})
|
|
56
|
+
.exec()
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 获取系统信息
|
|
62
|
+
* @returns {any} 系统信息对象
|
|
63
|
+
*/
|
|
64
|
+
export function getSystemInfo(): any {
|
|
65
|
+
try {
|
|
66
|
+
return uni.getSystemInfoSync()
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.error('获取系统信息失败:', e)
|
|
69
|
+
return {
|
|
70
|
+
windowWidth: 375,
|
|
71
|
+
windowHeight: 667,
|
|
72
|
+
pixelRatio: 2,
|
|
73
|
+
platform: 'unknown'
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* px 转 rpx
|
|
80
|
+
* @param {number} px - 像素值
|
|
81
|
+
* @returns {number} rpx值
|
|
82
|
+
*/
|
|
83
|
+
export function pxToRpx(px: number): number {
|
|
84
|
+
const systemInfo = getSystemInfo()
|
|
85
|
+
return px * 750 / systemInfo.windowWidth
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* rpx 转 px
|
|
90
|
+
* @param {number} rpx - rpx值
|
|
91
|
+
* @returns {number} 像素值
|
|
92
|
+
*/
|
|
93
|
+
export function rpxToPx(rpx: number): number {
|
|
94
|
+
const systemInfo = getSystemInfo()
|
|
95
|
+
return rpx * systemInfo.windowWidth / 750
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 添加单位
|
|
100
|
+
* @param {string | number} value - 值
|
|
101
|
+
* @param {string} unit - 单位,默认 'rpx'
|
|
102
|
+
* @returns {string} 带单位的值
|
|
103
|
+
*/
|
|
104
|
+
export function addUnit(value: string | number, unit: string = 'rpx'): string {
|
|
105
|
+
if (!value) return '0'
|
|
106
|
+
|
|
107
|
+
// 如果已经有单位,直接返回
|
|
108
|
+
if (typeof value === 'string') {
|
|
109
|
+
const hasUnit = /(rpx|px|%|vh|vw|rem|em)$/.test(value)
|
|
110
|
+
if (hasUnit) return value
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return `${value}${unit}`
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 获取元素样式
|
|
118
|
+
* @param {any} element - 元素
|
|
119
|
+
* @param {string} property - 样式属性
|
|
120
|
+
* @returns {string} 样式值
|
|
121
|
+
*/
|
|
122
|
+
export function getStyle(element: any, property: string): string {
|
|
123
|
+
if (!element) return ''
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
return element.style[property] || ''
|
|
127
|
+
} catch (e) {
|
|
128
|
+
console.error('获取样式失败:', e)
|
|
129
|
+
return ''
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 设置元素样式
|
|
135
|
+
* @param {any} element - 元素
|
|
136
|
+
* @param {string} property - 样式属性
|
|
137
|
+
* @param {string} value - 样式值
|
|
138
|
+
*/
|
|
139
|
+
export function setStyle(element: any, property: string, value: string): void {
|
|
140
|
+
if (!element) return
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
element.style[property] = value
|
|
144
|
+
} catch (e) {
|
|
145
|
+
console.error('设置样式失败:', e)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 批量设置样式
|
|
151
|
+
* @param {any} element - 元素
|
|
152
|
+
* @param {Record<string, string>} styles - 样式对象
|
|
153
|
+
*/
|
|
154
|
+
export function setStyles(element: any, styles: Record<string, string>): void {
|
|
155
|
+
if (!element || !styles) return
|
|
156
|
+
|
|
157
|
+
Object.keys(styles).forEach(key => {
|
|
158
|
+
setStyle(element, key, styles[key])
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 判断是否支持某个 CSS 属性
|
|
164
|
+
* @param {string} property - CSS 属性
|
|
165
|
+
* @returns {boolean} 是否支持
|
|
166
|
+
*/
|
|
167
|
+
export function supportsCss(property: string): boolean {
|
|
168
|
+
// #ifdef H5
|
|
169
|
+
if (typeof document !== 'undefined' && document.documentElement) {
|
|
170
|
+
const style = document.documentElement.style
|
|
171
|
+
return property in style
|
|
172
|
+
}
|
|
173
|
+
// #endif
|
|
174
|
+
|
|
175
|
+
// 非 H5 平台默认返回 true
|
|
176
|
+
return true
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 获取元素的计算样式
|
|
181
|
+
* @param {any} element - 元素
|
|
182
|
+
* @returns {any} 计算样式对象
|
|
183
|
+
*/
|
|
184
|
+
export function getComputedStyle(element: any): any {
|
|
185
|
+
// #ifdef H5
|
|
186
|
+
if (typeof window !== 'undefined' && window.getComputedStyle) {
|
|
187
|
+
return window.getComputedStyle(element)
|
|
188
|
+
}
|
|
189
|
+
// #endif
|
|
190
|
+
|
|
191
|
+
return element.style || {}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 判断元素是否在视口内
|
|
196
|
+
* @param {any} rect - 元素边界信息
|
|
197
|
+
* @param {number} offset - 偏移量
|
|
198
|
+
* @returns {boolean} 是否在视口内
|
|
199
|
+
*/
|
|
200
|
+
export function isInViewport(rect: any, offset: number = 0): boolean {
|
|
201
|
+
if (!rect) return false
|
|
202
|
+
|
|
203
|
+
const systemInfo = getSystemInfo()
|
|
204
|
+
const { windowHeight } = systemInfo
|
|
205
|
+
|
|
206
|
+
return rect.top < windowHeight + offset && rect.bottom > -offset
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 获取节点信息
|
|
211
|
+
* @param {string} selector - 选择器
|
|
212
|
+
* @param {any} instance - 组件实例
|
|
213
|
+
* @returns {Promise<any>} 节点信息
|
|
214
|
+
*/
|
|
215
|
+
export function getNodeInfo(selector: string, instance: any): Promise<any> {
|
|
216
|
+
return new Promise((resolve) => {
|
|
217
|
+
uni.createSelectorQuery()
|
|
218
|
+
.in(instance)
|
|
219
|
+
.select(selector)
|
|
220
|
+
.fields({
|
|
221
|
+
id: true,
|
|
222
|
+
dataset: true,
|
|
223
|
+
rect: true,
|
|
224
|
+
size: true,
|
|
225
|
+
scrollOffset: true,
|
|
226
|
+
properties: ['scrollX', 'scrollY']
|
|
227
|
+
}, (res: any) => {
|
|
228
|
+
resolve(res)
|
|
229
|
+
})
|
|
230
|
+
.exec()
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* 平滑滚动到指定位置
|
|
236
|
+
* @param {number} scrollTop - 滚动位置
|
|
237
|
+
* @param {number} duration - 动画时长
|
|
238
|
+
* @param {string} selector - 选择器
|
|
239
|
+
*/
|
|
240
|
+
export function smoothScrollTo(scrollTop: number, duration: number = 300, selector: string = ''): void {
|
|
241
|
+
if (selector) {
|
|
242
|
+
uni.pageScrollTo({
|
|
243
|
+
selector,
|
|
244
|
+
duration
|
|
245
|
+
})
|
|
246
|
+
} else {
|
|
247
|
+
uni.pageScrollTo({
|
|
248
|
+
scrollTop,
|
|
249
|
+
duration
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* 获取安全区域信息
|
|
256
|
+
* @returns {any} 安全区域信息
|
|
257
|
+
*/
|
|
258
|
+
export function getSafeArea(): any {
|
|
259
|
+
const systemInfo = getSystemInfo()
|
|
260
|
+
const { safeArea, screenHeight, statusBarHeight = 0 } = systemInfo
|
|
261
|
+
|
|
262
|
+
if (safeArea) {
|
|
263
|
+
return safeArea
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// 如果没有 safeArea,计算一个默认值
|
|
267
|
+
return {
|
|
268
|
+
top: statusBarHeight,
|
|
269
|
+
bottom: screenHeight,
|
|
270
|
+
left: 0,
|
|
271
|
+
right: systemInfo.windowWidth,
|
|
272
|
+
width: systemInfo.windowWidth,
|
|
273
|
+
height: screenHeight - statusBarHeight
|
|
274
|
+
}
|
|
275
|
+
}
|