Skip to content

框架设计

本页详细介绍 SinleUI 的整体架构、核心机制与设计理念,帮助您理解框架如何工作、为何这样设计。

概述

SinleUI 是一个面向 uni-app x 蒸汽模式(vapor)的轻量级移动端 UI 框架,以 uni_modules 形式分发,目标平台为 Android(Kotlin)与 Web(JavaScript),未来计划适配鸿蒙、iOS 与小程序。

框架坚持以下设计原则:

  • 简洁轻量:核心无运行时依赖,按需打包
  • 跨平台一致:通过条件编译与平台目录(utssdk/app-android 等)隔离平台差异
  • 主题化驱动:风格(Style)与主题(Theme)双层体系,全局一处修改、处处生效
  • 组合式 API:向组件与开发者提供 hooks 复用框架能力
  • 性能颜值平衡:追求更优秀的 UI 设计,一切设计都在考虑性能的情况下尽可能优化 UI 设计。

目录结构

uni_modules/sinle-ui/ 插件目录结构如下:

目录/文件说明
components/全部 sn-* 组件,每个组件一个独立目录(如 sn-button/sn-button.uvue
core/框架核心模块
core/snui.utsSnui 单例类定义,$snui 全局实例
core/state.uts全局响应式状态(主题、风格)、持久化与主题监听
core/types/index.uts全部核心类型定义与导出(SnColorBase、SnStyle 等)
core/theme/内置风格文件(default-styleink-stylechinese-style 等 6 套)与风格注册中心
core/utils/工具库分组静态类(Random、Basic、Easing、ObjectUtils、System、Resolve、Sort、Text、Ui、Perm、Verify)
core/utils/index.utssnu 聚合门面
core/color/颜色库(ColorLibTinyColor
core/date/日期库(DateLibDayuts、国际化)
core/private/内部钩子与机制(use-themeuse-styleuse-factorsuse-hoveruse-external-styleuse-backtoploggerdialog-store
pages/popups/全局弹窗页面(showModal、showActionsheet、showLoading)
pages_init.json注册插件内置弹窗页面
index.uts插件入口,统一导出全部公开 API

风格系统(Style)

一个应用可同时注册多套风格(皮肤),如现代、简约、古风、梦幻、科幻等。每套风格是一个 SnStyle 对象,包含:颜色集(亮/暗两套)、导航栏高度、亮/暗页面背景色,以及五个乘数与三个基础动画时长。

  • 注册与切换core/theme/index.uts 在框架加载时执行 initStyles() 注册内置风格;$snui.currentStyleId 切换风格(switchStyle 会深拷贝目标风格再替换当前风格,避免互相污染)。

  • 内置风格default(默认)、ink(水墨)、chinese(国风)、new-year(新年)、morandi-green(莫兰迪绿)、orange(活力橙)共 6 套。

  • 持久化switchStyle 与各 setter 修改后调用 persistCurrentStyle(),将当前完整风格写入 storage(key:sinleui_current_style),风格 id 单独存储(key:sinleui_current_style_id)。应用重启自动恢复。

  • 运行时微调:开发者可直接修改 $snui 上的乘数与颜色等属性,改的是当前风格对象,随后自动持久化,覆盖预置值。

    SnStyle

    一套完整风格(皮肤)对象,即内置风格文件导出的结构。

    字段类型描述
    idString风格唯一 id,如 'default'
    colorBasesSnColorBases亮/暗两套颜色集
    topbarHeightString导航栏高度(不含状态栏)
    lightBgColorString亮色模式页面默认背景色
    darkBgColorString暗色模式页面默认背景色
    marginFactorNumber外间距乘数
    paddingFactorNumber内间距乘数
    radiusFactorNumber圆角乘数
    fontsizeFactorNumber字号乘数
    aniTimeFactorNumber动画时长乘数
    aniTimeShortNumber基础短动画时长(ms)
    aniTimeNormalNumber基础标准动画时长(ms)
    aniTimeLongNumber基础长动画时长(ms)

主题系统(Theme)

主题指亮色(light)与暗色(dark)两种颜色模式。一套风格的 colorBases 包含两套 SnColorBase 颜色集。

  • 切换$snui.theme = 'light' | 'dark'autoTheme(默认开启)跟随系统外观,内部监听 uni.onOsThemeChange(App)/ window.matchMedia(Web)自动切换。
  • 状态栏同步:切换与初始化时会调用 syncStatusBarColor() 同步原生状态栏文字/背景色。
  • App 端原生主题:通过 uni.setAppTheme 同步系统暗黑模式,保证 window 等系统 UI 与页面一致。

core/state.uts 中导出的响应式状态构成了框架状态的根基:currentStyleIdcurrentStylecurrentThemeautoTheme,以及由 currentStyle × currentTheme 计算出的 colors(当前颜色集)。


颜色系统

SnColorBase 定义了完整的语义化颜色集,分为功能色特殊色两类(字段明细见核心类型)。

功能色共 5 种语义:primary(主色)、info(信息)、success(成功)、error(错误)、warning(警告)。每种功能色在亮/暗模式下各有 3 个深浅程度(原色 / Light 更浅 / Dark 更深),每个程度配套 Active(激活态)与 Text(该色背景上的文字前景色)。

注意:后缀带 Dark 的是比原色更深的颜色,并非暗黑主题专属;带 Light 的是更浅的颜色。暗黑主题与亮色主题各自拥有独立的 SnColorBase 对象。

  • 页面注入sn-pageonLoad 时把当前 colors 注入为 CSS 变量(--sn-* 命名),监听风格/主题变化做差量更新(仅更新变化的颜色变量)。页面内所有组件与弹出层(必须位于 sn-page 根节点下)通过 var(--sn-xxx) 引用即随主题自动切换。
  • $ 简化语法:颜色类 props 统一经 useResolve 钩子的 resolveColor 处理,$primaryTextDark 自动转换为 var(--sn-primary-text-dark),非 $ 开头的值原样返回。

大小乘数与动画时长

框架通过五个全局乘数控制 UI 的密度与动效节奏,均可在 $snui 上读写并持久化:

乘数属性作用
fontsizeFactor字号乘数
radiusFactor圆角乘数
marginFactor外间距乘数
paddingFactor内间距乘数
aniTimeFactor动画时长乘数

还提供了三个常用动画时长,以保持应用全局动画的一致性: $snui.aniTimeShort(150ms) / $snui.aniTimeNormal(250ms) / $snui.aniTimeLong(400ms)。这些常用动画时长会自动适配 aniTimeFactor 机制,无需您自行处理。并提供 utscss 两种使用方法,CSS 变量由 sn-page--ani-time-short/normal/long CSS 变量注入页面。

$ 动态尺寸语法

尺寸类 props 统一交给 useResolve 钩子的 resolveSize / resolveSizeNum 处理——16px(无 $)返回原始值;:16(number)返回原始值;"$16px"(带 $)提取数值乘以对应乘数。解析类型由 SnResolveType 指定(font / radius / margin / padding / aniTime)。


工具库三层架构

  1. 分组静态类core/utils/*.uts):按功能拆分为 Random、Basic、Easing、ObjectUtils、System、Resolve、Sort、Text、Ui、Perm、Verify 共 11 组。
  2. 聚合门面core/utils/index.uts):snu 静态类,每个方法一行转发。
  3. 插件出口index.uts):export { snu }

用户侧统一使用 snu.xxx;组件内部为减小体积直接导入分组类。平台相关方法(系统、权限等)经 sinle-api 插件按平台目录(utssdk/app-android)分别实现,无需条件编译。


钩子

框架向组件与开发者暴露 4 个核心 hooks(useTheme / useStyle / useFactors / useHover),详见钩子。组件的主题、风格、乘数、点击态、解析等能力均经由 hooks 获取,保证响应式(状态变化自动触发重渲染)。对外导出的 hooks 有 useTheme / useStyle / useFactors / useHover / useResolve;另有内部复用 hooks:useExternalStyle(外部样式转字符串)、useBacktop(滚动容器与返回顶部联动)。


全局弹窗机制

snu.showToast / snu.showModal / snu.showActionsheet / snu.showLoading 实现"任意位置调用、无需放置组件"的全局弹窗:

  1. 框架内置 3 个弹窗页面(showModal、showActionsheet、showLoading),经 pages_init.json 注册;
  2. core/private/dialog-store.uts 提供一个键值存储,保存本次弹窗的配置对象;
  3. snu 的 UI 方法把配置写入 dialog-store,并通过 uni.openDialogPage 打开对应弹窗页;弹窗页 onLoad 时按 id 取回配置并展示,交互完成后触发 success/fail/complete 回调并关闭页面。

showToasthighlight 类轻提示由组件实现而非页面,其中 showToast 同样可在任意位置调用。


日志与错误

  • 日志:框架内部统一使用 core/private/logger.uts(转发自 sinle-logger 插件)输出 [Snui] 前缀日志,受 $snui.logging 控制开关。组件禁止直接使用 console
  • 错误UniError 为框架统一错误类型(遵循 uni 错误规范),全局 API 失败时通过 fail 回调返回,详见错误与日志

国际化(i18n)

SinleUI 内置一套独立于宿主项目的国际化系统:框架内所有组件内置文本(确定/取消/加载中/上传/刷新/签名/扫码等)默认均通过翻译函数渲染,不含任何硬编码文字,并随组件语言自动切换。

独立性

插件 i18n 与宿主项目自身的 i18n(如项目按 uni-app x 国际化文档 搭建的 vue-i18n)互相独立、互不影响。插件不依赖项目是否接入 vue-i18n,因此 sinle-* 插件可安全地用于任何已适配或未适配 i18n 的项目。

支持的语言

共 11 种:

  • 简体中文 zh-Hans
  • 英语 en
  • 法语 fr
  • 俄语 ru
  • 日语 ja
  • 繁体中文 zh-Hant
  • 韩语 ko
  • 西班牙语 es
  • 德语 de
  • 意大利语 it
  • 葡萄牙语 pt

默认语言策略

初始化时按「存储值 > 系统语言(自动匹配近似标签)> 简体中文」取默认值;切换后自动持久化(storage key:sinleui_current_locale),重启恢复。

使用方式

typescript
import { $snui, t, locale, useI18n, SUPPORTED_LOCALES } from '@/uni_modules/sinle-ui'

// 切换组件语言(全局生效,自动持久化)
$snui.locale = 'en'

// 组件内翻译(响应式,语言变化自动重渲染)
const label = t('common.confirm')
const range = t('calendar.rangePrompt', { maxRange: '7' } as UTSJSONObject) // 参数插值

// hooks 形式(模板中使用 t / locale)
const { t, locale } = useI18n()

// 支持的语言列表(含本地化名称,可直接渲染为语言选择器)
SUPPORTED_LOCALES // [{ code: 'zh-Hans', name: '简体中文' }, ...]

消息文件

  • 插件消息:uni_modules/sinle-ui/core/i18n/locale/*.uts(每语言一个文件,键形如 common.confirmloadmore.more)。
  • 组件 props 默认值均已改为空串 + t() 兜底:用户传入自定义文本时优先显示用户值,否则回落到当前语言。
  • 日历、日期格式化等组件(weekdays / 月份 / 相对时间)同样接入插件 i18n。

使用 MIT 协议