import type { CSSProperties } from 'vue' import trim from './trim' import test from './test' export function isValidValue(value: any): boolean { if (test.isEmpty(value)) return false if (typeof value === 'string') { const trimmed = trim(value).toLowerCase() return trimmed !== 'null' && trimmed !== 'undefined' && trimmed !== '' } return true } /** * 将 CSS 字符串解析为对象 */ export function cssStrToObj(str: string): object { const result = {} if (!isValidValue(str)) return result const styleStr = trim(String(str)) if (!isValidValue(styleStr)) return result const declarations = styleStr.split(';') declarations.forEach((decl) => { const [prop, ...values] = decl.split(':').map(s => s.trim()) const value = values.join(':') if (prop && value) { const camelProp = prop.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase()); (result as Record)[camelProp] = value } }) return result } /** * 将 CSS 对象转换为 CSS 字符串 */ export function cssObjToStr(obj: object): string { if (!isValidValue(obj) || typeof obj !== 'object') return '' return ( `${Object.entries(obj) .map(([key, value]) => { if (!isValidValue(value)) return '' // 驼峰转短横线 const kebab = key.replace(/([A-Z])/g, '-$1').toLowerCase() return `${kebab}: ${value}` }) .filter(Boolean) .join('; ')};` ) } /** * 合并多个 CSS 输入(对象或字符串),返回一个 CSS 对象 */ export function mergeStyles(...args: (object | string)[]): CSSProperties { const result = {} as Record for (let i = 0; i < args.length; i++) { const arg = args[i] if (!isValidValue(arg)) return result as CSSProperties if (typeof arg === 'string') { Object.assign(result, cssStrToObj(arg)) } else if (test.object(arg)) { const cleanedObj: Record = {} Object.keys(arg).forEach((key) => { const value = (arg as Record)[key] if (isValidValue(value)) { // 有效 cleanedObj[key] = value } }) Object.assign(result, cleanedObj) } } return result } /** * 合并为 CSS 字符串 */ export function mergeCssStrings(...args: (object | string)[]): string { const obj = mergeStyles(...args) return cssObjToStr(obj) }