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

Как share используется на каждой платформе

core пакета share — это чистые функции, не содержащие никакой реактивности. UI-библиотеки платформ делают только одно: привязывают вывод чистых функций к шаблону и передают пользовательский ввод обратно в чистые функции. Ниже — формы разводки для четырёх платформ.

Разводка каждого компонента состоит из трёх шагов:

  1. На стороне фреймворка хранится состояние (ref / useState / реактивные data)
  2. Взаимодействие пользователя → вызов чистой функции core, вычисляющей новое состояние → запись обратно
  3. В шаблоне вызываются чистые функции вычисления классов / набора aria-атрибутов
// Сторона core (не зависит от фреймворка, этот репозиторий)
export function getSwitchClasses(state: LhSwitchState): string
export function getSwitchAria(state: LhSwitchState): Record<string, string>
export function toggleSwitch(state: LhSwitchState, checked: boolean): LhSwitchState
<script setup lang="ts">
import { ref, computed } from 'vue'
import { getSwitchClasses, getSwitchAria, toggleSwitch } from '@lh-ui/share/core/switch'
const checked = ref(false)
const classes = computed(() => getSwitchClasses({ checked: checked.value, disabled: false }))
const aria = computed(() => getSwitchAria({ checked: checked.value }))
function onToggle() {
checked.value = toggleSwitch({ checked: checked.value }, !checked.value).checked
}
</script>
<template>
<button :class="classes" v-bind="aria" @click="onToggle">
<span class="lh-switch__handle" />
</button>
</template>
<style lang="scss">
@use '@lh-ui/share/styles/switch';
</style>

Стили инъектируются полностью через side-effect во входном файле библиотеки, поэтому в компоненте их обычно подключать отдельно не нужно (см. Стратегии инъекции стилей).

<script lang="ts">
import { getSwitchClasses, getSwitchAria, toggleSwitch } from '@lh-ui/share/core/switch'
export default {
name: 'LhSwitch',
data() {
return { checked: false }
},
computed: {
classes() {
return getSwitchClasses({ checked: this.checked, disabled: false })
},
aria() {
return getSwitchAria({ checked: this.checked })
},
},
methods: {
onToggle() {
this.checked = toggleSwitch({ checked: this.checked }, !this.checked).checked
},
},
}
</script>

Стили пользователь подключает по требованию:

import '@lh-ui/vue2/theme.css'
import '@lh-ui/vue2/style/switch'

useMemo заменяет computed; изменение состояния и так реактивно запускает перерендер:

import { memo, useMemo, useState } from 'react'
import {
getSwitchClasses,
getSwitchAria,
toggleSwitch,
} from '@lh-ui/share/core/switch'
import '@lh-ui/react/style/switch'
export const LhSwitch = memo(function LhSwitch() {
const [checked, setChecked] = useState(false)
const classes = useMemo(
() => getSwitchClasses({ checked, disabled: false }),
[checked],
)
const aria = useMemo(() => getSwitchAria({ checked }), [checked])
return (
<button
type="button"
className={classes}
{...aria}
onClick={() => setChecked((c) => !c)}
>
<span className="lh-switch__handle" />
</button>
)
})

На <view> / <text> в uniapp нельзя свободно навешивать aria-атрибуты: результат getSwitchAria на стороне мини-программ будет отфильтрован; на платформах app / h5 он остаётся доступен. Привязка классов идёт через строку или массив :class:

<template>
<view :class="classes" @tap="onToggle">
<view class="lh-switch__handle" />
</view>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { getSwitchClasses, toggleSwitch } from '@lh-ui/share/core/switch'
const checked = ref(false)
const classes = computed(() => getSwitchClasses({ checked: checked.value }))
function onToggle() {
checked.value = !checked.value
}
</script>

Интернационализация: один emitter, четыре способа подписки

Заголовок раздела «Интернационализация: один emitter, четыре способа подписки»

LhLocale — это чистый генератор событий; version увеличивается при любом изменении языка. Каждая платформа превращает его в свой сигнал перерендера:

Платформа Разводка
vue2 / vue3 / uniapp ref(lhlocale.version) + lhlocale.subscribe(v => version.value = v)
react useSyncExternalStore(lhlocale.subscribe, () => lhlocale.version)
import { lhlocale } from '@lh-ui/share/locales'
lhlocale.setLocale('en-US') // Переключение: version увеличивается и рассылается
const text = lhlocale.t('input.placeholder')

Живая демонстрация — в справочнике по интернационализации.

Локальная линковка: изменения исходников share действуют сразу

Заголовок раздела «Локальная линковка: изменения исходников share действуют сразу»

При семейной раскладке конфигурации dev / test UI-библиотек указывают через alias на соседний репозиторий lh-ui-share/, и в dev-режиме используются TS / SCSS-исходники, а не сборочные артефакты. Новый глубоко расположенный файл (например, core/foo/bar.ts) сразу доступен в dev-режиме, но если sync-exports не запущен, на стороне npm не будет соответствующего ключа exports — перед релизом обязательно выполнять полный pnpm build, иначе у пользователей ниже по потоку после pnpm up возникнет MODULE_NOT_FOUND.

Copyright © 2024-2026 FengMo WenXue