158 lines
4.5 KiB
TypeScript
158 lines
4.5 KiB
TypeScript
// @ts-nocheck
|
||
/**
|
||
* 驼峰命名转短横线命名
|
||
* @param str - 需要转换的字符串
|
||
* @returns 转换后的短横线命名字符串
|
||
*/
|
||
function toKebabCase(str : string) : string {
|
||
return str
|
||
// 1. 字母+数字+连续大写视为整体:"e2XL" → "e-2XL"
|
||
.replace(/([a-z])(\d+[A-Z]{2,})/g, '$1-$2')
|
||
// 2. 字母+连续大写视为整体:"eSM" → "e-SM", "sXS" → "s-XS"
|
||
.replace(/([a-z])([A-Z]{2,})/g, '$1-$2')
|
||
// 3. 小写+大写常规边界:"tS" → "t-S", "eB" → "e-B"
|
||
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
||
// 4. 字母+数字边界:"y50" → "y-50"
|
||
.replace(/([a-zA-Z])(\d+)/g, '$1-$2')
|
||
.toLowerCase()
|
||
}
|
||
|
||
// #ifndef UNI-APP-X
|
||
type UTSJSONObject = Record<string, any>
|
||
// #endif
|
||
|
||
export type StyleProp =
|
||
| string
|
||
| UTSJSONObject
|
||
| null
|
||
| undefined
|
||
| false
|
||
| StyleProp[]
|
||
|
||
/**
|
||
* 把样式对象拼接成字符串,解决小程序不支持 styleObject 的问题
|
||
* @description 支持多种参数类型的样式拼接,包括字符串、对象和数组
|
||
* @param args 样式参数,可以是字符串、对象、null、undefined、false 或数组
|
||
* @returns 拼接后的样式字符串
|
||
* @example
|
||
* stringifyStyle('color: red') // 'color: red;'
|
||
* stringifyStyle({ color: 'red', fontSize: '14px' }) // 'color: red;font-size: 14px;'
|
||
* stringifyStyle(['color: red', 'background: blue']) // 'color: red;background: blue;'
|
||
* stringifyStyle('color: red', null, 'background: blue') // 'color: red;background: blue;'
|
||
* stringifyStyle({ color: 'red', display: false, opacity: 0 }) // 'color: red;opacity: 0;'
|
||
*/
|
||
export function stringifyStyle(...args : StyleProp[]) : string {
|
||
return stringifyStyleArray(args)
|
||
}
|
||
|
||
function isValidStyleValue(value : StyleProp) : boolean {
|
||
if (value == null) return false; // 排除 null/undefined
|
||
if (typeof value == 'boolean') return false // 排除所有布尔值
|
||
if (value == 0) return true
|
||
if (value == '') return false; // 排除空字符串
|
||
if (typeof value == 'number') {
|
||
return isFinite(value as number); // 允许有效数字,排除 NaN/Infinity
|
||
}
|
||
|
||
return true; // 字符串和其他情况
|
||
}
|
||
|
||
|
||
/**
|
||
* 处理数组的样式
|
||
* @description 用于内部递归处理数组类型的样式
|
||
* @param args 样式数组
|
||
* @returns 拼接后的样式字符串
|
||
*/
|
||
function stringifyStyleArray(args : StyleProp[]) : string {
|
||
const result : string[] = []
|
||
for (let i = 0; i < args.length; i++) {
|
||
const arg = args[i]
|
||
if (!isValidStyleValue(arg)) continue
|
||
if (typeof arg == 'string') {
|
||
result.push(arg as string)
|
||
} else if (Array.isArray(arg)) {
|
||
if ((arg as StyleProp[]).length > 0) {
|
||
const style = stringifyStyleArray(arg)
|
||
if (style != '') {
|
||
result.push(style)
|
||
}
|
||
}
|
||
} else if (typeof arg == 'object') {
|
||
// #ifndef APP-ANDROID
|
||
for (const key in arg) {
|
||
const value = arg[key]
|
||
if (isValidStyleValue(value)) {
|
||
result.push(`${toKebabCase(key)}:${value}`)
|
||
}
|
||
}
|
||
// #endif
|
||
// #ifdef APP-ANDROID
|
||
// #ifdef VUE3-VAPOR
|
||
for (const key in arg) {
|
||
const value = arg[key]
|
||
if (isValidStyleValue(value)) {
|
||
result.push(`${toKebabCase(key)}:${value}`)
|
||
}
|
||
}
|
||
// #endif
|
||
// #ifndef VUE3-VAPOR
|
||
(arg as UTSJSONObject).toMap().forEach((value, key) => {
|
||
if (isValidStyleValue(value)) {
|
||
result.push(`${toKebabCase(key)}:${value}`)
|
||
}
|
||
})
|
||
// #endif
|
||
// #endif
|
||
}
|
||
}
|
||
|
||
return result.join(';')
|
||
}
|
||
|
||
/**
|
||
* 将对象转换为 CSS 自定义属性字符串
|
||
* @param obj - 包含主题变量的对象
|
||
* @param prefix - CSS 变量的前缀,默认为 '--l-'
|
||
* @returns CSS 变量字符串,例如 '--l-image-color: red; --l-bg: blue;'
|
||
*/
|
||
export function toCssVars(obj : UTSJSONObject, prefix = '--l-') : string {
|
||
const cssVars : string[] = [];
|
||
|
||
if (typeof obj == 'object') {
|
||
// #ifndef APP-ANDROID
|
||
for (const key in obj) {
|
||
const value = obj[key]
|
||
if (isValidStyleValue(value)) {
|
||
const cssVarName = prefix + toKebabCase(key);
|
||
cssVars.push(`${cssVarName}:${value}`)
|
||
}
|
||
|
||
}
|
||
// #endif
|
||
// #ifdef APP-ANDROID
|
||
// #ifdef VUE3-VAPOR
|
||
for (const key in obj) {
|
||
const value = obj[key]
|
||
if (isValidStyleValue(value)) {
|
||
const cssVarName = prefix + toKebabCase(key);
|
||
cssVars.push(`${cssVarName}:${value}`)
|
||
}
|
||
|
||
}
|
||
// #endif
|
||
// #ifndef VUE3-VAPOR
|
||
(obj as UTSJSONObject).toMap().forEach((value, key) => {
|
||
if (isValidStyleValue(value)) {
|
||
const cssVarName = prefix + toKebabCase(key);
|
||
cssVars.push(`${cssVarName}:${value}`)
|
||
}
|
||
})
|
||
// #endif
|
||
// #endif
|
||
|
||
}
|
||
|
||
|
||
return cssVars.join(';') + ';'; // 加上最后的分号以符合 CSS 规范
|
||
} |