Перейти к содержимому

sx —— стенография стилей

sx — это стенография инлайн-стилей lh-ui: mt: 4 вместо style="margin-top: 32px", p: 2 вместо четырёх padding, записанных разом. Это не Tailwind (никакой генерации class-имен, никакого CSS): на этапе выполнения пакет props напрямую вычисляется в Record<string, string>, который UI-слой привязывает к :style.

  • Внутри библиотеки компонентов: sx избавляет от новых props на уровне «мелкой подстройки раскладки» — <LhButton sx={{ mt: 2 }} /> уже отодвигает верхний отступ.
  • Для интервалов, которые должны динамически зависеть от данных: пересчёт числа в px (×8) даёт устойчивую шкалу для семантики вроде «подвинь меня чуть ближе».
  • Не использовать: для систематического визуального дизайна. sx — это «временная подстройка в точке вызова»; дизайн-токены, такие как цвет темы или высота контролов, по-прежнему живут в CSS-переменных (см. тематическая система); записать color: 'var(--lh-primary-color)' в sx можно, но рекомендуется, чтобы компонент потреблял токены напрямую.
// точечный импорт (рекомендуется, удобен для tree-shaking)
import { sxToStyle, mergeSx } from '@lh-ui/share/core/shared/sx'
import type { LhSxProps } from '@lh-ui/share/core/shared/sx'
// или из сводного входа
import { sxToStyle } from '@lh-ui/share/core/shared'
Функция Сигнатура Возвращает Назначение
sxToStyle (sx: LhSxProps) => Record<string, string> объект инлайн-стилей вычисляет пакет props sx в CSS-стили
mergeSx (...list: (LhSxProps | undefined | null)[]) => LhSxProps объединённый sx последующий перекрывает предыдущий; нужен UI-слою для комбинирования «sx по умолчанию + sx вызывающей стороны»

«Одна сторона > пара осей > сокращение», и это не зависит от порядка записи ключей. Реализация записывает свойства в объект в фиксированном порядке сокращение → пара осей → одна сторона, и записанное позже перекрывает записанное раньше, поэтому как бы вы ни расположили ключи:

sxToStyle({ m: 2, mt: 4 }) // { marginTop: '32px', marginRight: '16px', marginBottom: '16px', marginLeft: '16px' }
sxToStyle({ mt: 4, m: 2 }) // абсолютно то же самое
sxToStyle({ my: 2, mt: 4 }) // marginTop по одной стороне побеждает: 32px; mb остаётся 16px

Это правило позволяет библиотеке безопасно писать «пакет по умолчанию + пользовательское переопределение»: переданный пользователем mt обязательно перекроет внутренний m компонента.

  • Числа пересчитываются по ×8px: mt: 4 → 32px. 8 — база интервалов lh-ui (та же шкала, что у токенов --lh-spacing-*).
  • Строки проходят как есть: w: '50%' → 50%, p: '1rem' → 1rem.
  • Ключи раскладки не пересчитываются: значения display / flex / flexDirection / alignItems / justifyContent записываются как строки напрямую (flexDirection: 'column' не превратится в columnpx).
  • Все ключи единообразно проверяются через !== undefined: передача пустой строки '' считается явной очисткой и будет записана.
export interface LhSxProps {
// размер
w?: string | number
h?: string | number
// внешние отступы: одна сторона / пара осей / сокращение
mt?: string | number
mr?: string | number
mb?: string | number
ml?: string | number
my?: string | number
mx?: string | number
m?: string | number
// внутренние отступы: та же структура
pt?: string | number
pr?: string | number
pb?: string | number
pl?: string | number
py?: string | number
px?: string | number
p?: string | number
// раскладка
display?: string
flex?: string
flexDirection?: 'row' | 'column'
alignItems?: string
justifyContent?: string
// совместимость с пользовательскими ключами downstream; неизвестные ключи тихо отбрасываются
[key: string]: any
}

Индексная сигнатура [key: string]: any — намеренная: каждая UI-библиотека объединяет sx?: LhSxProps со специфичными атрибутами компонента в собственном типе LhXxxProps, и индексная сигнатура не даёт типам конфликтовать; неизвестные ключи отбрасываются при вычислении и не просачиваются в стили.

sxToStyle({ mt: 2, px: 3, display: 'flex', alignItems: 'center' })
// {
// marginTop: '16px',
// paddingLeft: '24px',
// paddingRight: '24px',
// display: 'flex',
// alignItems: 'center',
// }
<!-- Vue3 / Vue2: напрямую в :style -->
<template>
<lh-button :style="sxToStyle($props.sx)">Кнопка</lh-button>
</template>
// React
<div style={sxToStyle({ my: 4, w: '100%' })} />
// uniapp: sxToStyle возвращает обычный объект, он идёт прямо в привязку style
// (пересчёт чисел ×8px на не-h5 концах зависит от платформы — это обрабатывает UI-слой)

Типичное применение mergeSx — объединение со значениями по умолчанию внутри компонента:

// внутри компонента
const merged = mergeSx({ py: 2, px: 4 }, props.sx) // пользовательский sx перекрывает умолчания
const style = sxToStyle(merged) // вычисление один раз, правило приоритета применяется единожды
  • mergeSx — поверхностное слияние (Object.assign), без рекурсии; значения в sx — скаляры, поверхностного слияния достаточно.
  • sxToStyle при ложном значении возвращает {}: sxToStyle(undefined) — пустой объект, UI-слой может вызывать не глядя.
  • База пересчёта 8px выровнена с токенной системой, но сам sx не ссылается на CSS-переменные — он выдаёт вычисленный литерал; он подходит для сценария «в этом вызове нужно чуть сдвинуть» и не подходит для сценария «меняется вместе с темой».
  • Кросс-платформенность: rpx на не-h5 концах uniapp пересчитывается в UI-слое; ядро sx выдаёт только px.
@lh-ui/share/core/sx → sxToStyle( )
返回值
(填好参数后点运行)

Copyright © 2024-2026 FengMo WenXue