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
Заголовок раздела «Правило приоритета sxToStyle»«Одна сторона > пара осей > сокращение», и это не зависит от порядка записи ключей. Реализация записывает свойства в объект в фиксированном порядке сокращение → пара осей → одна сторона, и записанное позже перекрывает записанное раньше, поэтому как бы вы ни расположили ключи:
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