avatar —— Аватар
Компонент аватара работает с тремя формами контента: изображение, текст и иконка — и должен корректно деградировать, если изображение не загрузилось или адрес некорректен. core/avatar выделяет «извлечение текста» и «определение источника изображения» в чистые функции — эти два решения должны быть полностью идентичны на всех платформах, иначе возникает расхождение в духе «Vue3 показывает текст, а uniapp показывает сломанное изображение».
Когда использовать
Заголовок раздела «Когда использовать»- При реализации
LhAvatarна каждой платформе: если изображение доступно — отрисовываетсяimg, иначе первый символ, извлечённыйgetAvatarText, а если ничего нет — плейсхолдер с иконкой. - Сценарии, где в пользовательской системе берётся «первый символ имени» в качестве аватара по умолчанию.
- Не следует использовать: обрезка и загрузка изображений. Это задача
LhUploadплюс бизнес-логики.
import { getAvatarClassNames, getAvatarText, isImageSource } from '@lh-ui/share/core/avatar'import type { LhAvatarState, LhAvatarShape } from '@lh-ui/share/core/avatar'Замысел
Заголовок раздела «Замысел»getAvatarText использует codePointAt(0) + String.fromCodePoint, а не str[0] — это легко упускаемая ловушка: '😀'[0] возвращает половину суррогатной пары (\uD83D), которая отображается как сломанный квадрат. Извлечение по кодовой точке безопасно для emoji и символов дополнительных плоскостей (многие редкие китайские иероглифы).
Регулярное выражение в isImageSource выполняет лишь грубую проверку доступности, а не валидацию безопасности: строки, начинающиеся с http(s)://, data:image/, абсолютного пути / или относительного пути ./ / ../, считаются адресами изображений. Его назначение — «решить, стоит ли пытаться отрисовать img», а реальные ошибки загрузки перехватываются событием error элемента img (UI-слой переключается на текстовое состояние).
Таблица функций
Заголовок раздела «Таблица функций»| Функция | Сигнатура | Возврат | Назначение |
|---|---|---|---|
getAvatarClassNames |
(state: LhAvatarState) => string[] |
массив классов | модификаторы формы и размера |
getAvatarText |
(source: string) => string |
первый символ или '' |
извлекает отображаемый символ из текста |
isImageSource |
(src: string | undefined) => boolean |
логическое | стоит ли адрес изображения попытаться отрисовать |
Граничные детали:
getAvatarText('')→'';getAvatarText(' 水墨 ')→'水'(сначала trim);getAvatarText('Alice')→'A'.getAvatarTextвозвращает'', еслиcodePointAt(0)возвращает undefined (пустая строка отсекается через trim, поэтому теоретически это недостижимо).isImageSource(undefined)→false;isImageSource('')→false.
Определения типов
Заголовок раздела «Определения типов»export type LhAvatarShape = 'circle' | 'square'
export interface LhAvatarState { size: LhComponentSize shape: LhAvatarShape}Доступность
Заголовок раздела «Доступность»core/avatar не выводит набор aria-атрибутов, так как обработка аватара зависит от формы контента:
- Аватар-изображение: используется нативный
<img>,altобязателен (например, «Аватар Ивана»). Не оставляйте alt пустым — пустой alt означает «декоративное изображение», тогда как аватар обычно несёт информацию о личности. - Текстовый аватар: текст сам по себе читаемое содержимое, дополнительная обработка не нужна.
- Аватар-иконка (плейсхолдер анонимного пользователя): иконка проходит через
getIconAria({ decorative: false, label: 'Анонимный пользователь' }).
Примеры использования
Заголовок раздела «Примеры использования»import { getAvatarText, isImageSource } from '@lh-ui/share/core/avatar'
getAvatarText('Ван Сяомин') // 'В'getAvatarText('Alice Smith') // 'A'getAvatarText('😀хаха') // '😀'isImageSource('https://a.com/1.png') // trueisImageSource('data:image/png;base64,...') // trueisImageSource(undefined) // false<!-- Vue3 --><div :class="getAvatarClassNames({ size, shape })"> <img v-if="isImage && !error" :src="src" :alt="alt" @error="error = true" /> <span v-else-if="text" class="lh-avatar__text">{{ text }}</span> <LhIcon v-else name="user" :decorative="false" label="Анонимный пользователь" /></div>// Reactconst text = getAvatarText(name)const showImg = isImageSource(src) && !imgErrorreturn ( <div className={getAvatarClassNames({ size, shape }).join(' ')}> {showImg ? <img src={src} alt={alt} onError={() => setImgError(true)} /> : text ? <span className="lh-avatar__text">{text}</span> : <LhIcon name="user" decorative={false} label="Анонимный пользователь" />} </div>)// uniapp: у компонента <image> есть событие @error, логика та же;// для текстовых аватаров на не-h5 платформах следите за запасными шрифтами// (редким иероглифам может не хватать глифов)Стили и токены
Заголовок раздела «Стили и токены»| Класс | Семантика |
|---|---|
.lh-avatar |
базовый класс: фиксированные ширина/высота, скрытие переполнения, центрирование |
.lh-avatar--{mini|small|medium|large|x-large} |
размерная шкала |
.lh-avatar--circle / .lh-avatar--square |
форма (радиус скругления) |
.lh-avatar__img |
изображение: заполнение + object-fit |
.lh-avatar__text |
текст: центрирование, белый цвет, масштабирование по размеру |
.lh-avatar__icon |
плейсхолдер-иконка |
Фон аватара по умолчанию — токен основного цвета; в многоаватарных сценариях (например, группы аватаров) UI-слой каждой платформы может раскрашивать их по хэшу имени, core в этом не участвует.
Замечания
Заголовок раздела «Замечания»- Не используйте
str[0]илиstr.charAt(0)для извлечения первого символа в UI-слое — emoji и редкие иероглифы будут обрезаны в нечитаемые обрывки; используйте единыйgetAvatarText. isImageSource, возвращая true, не означает, что изображение существует, — лишь «стоит попробовать». ОткатonErrorобязателен.square— не прямой угол, а небольшое скругление (для визуального баланса): аватары с прямыми углами в дизайне кажутся слишком резкими.object-fitизображения по умолчаниюcover, поэтому лицо может быть обрезано по краям — бизнес-задачам часто требуется тонкая настройкаobject-position, это обрабатывается в UI-слое каждой платформы.
@lh-ui/share/core/avatar → getAvatarText( )(填好参数后点运行)Copyright © 2024-2026 FengMo WenXue