@xwink/ui

    useTheme

    明暗档的单一入口。读写用户选择、解析出当前生效档写进 html[data-theme],并同步 color-scheme ——滚动条、下拉、日期选择这些原生控件不吃 --ui-* token,只认它。

    XThemeToggle 只是它的一个操作面,同页放几个都是同一份状态。

    基础

    选择、生效档与 toggle

    返回值

    名称类型说明
    preferenceRef<'light' | 'dark' | 'auto'>用户的选择,可写;auto 如实保留
    resolvedReadonly<Ref<'light' | 'dark'>>当前真正生效的档,auto 时跟随系统
    isDarkComputedRef<boolean>resolved === 'dark'
    systemComputedRef<'light' | 'dark'>系统外观本身
    toggle()() => void在明暗间翻转,落到一个明确档位(不再是 auto)
    setHostTheme(theme)(theme?: 'light' | 'dark') => void嵌入协议用:宿主指定这一页显示哪档,不持久化、不改用户偏好;传 undefined 撤销

    选择与生效档要分开取:跨窗口下发主题(比如 Console 把档位交给 iframe 里的管理子站)必须传 resolved,把 auto 原样传过去等于让对方回落它自己的默认档。

    全站共享

    缺省时偏好存在可注册域的 Cookie(xwink-ui-theme)上,而不是 localStorage:localStorage 按源隔离, console / chat / home / uc 各存一份;Cookie 按域共享,任何一个站点切换,其它站点在回到前台时跟上 (支持 cookieStore 的浏览器实时)。可注册域由逐级试写 Cookie 探测,本地 localhost 的 Cookie 不分端口, 开发环境同样全站一份。旧的 xwink-ui:theme localStorage 偏好在首次读取时迁移过去。

    另存一份 xwink-ui-theme-resolved(上次生效档,只有 light / dark),SSR 宿主靠它在服务端就渲染出 正确档位,跟随系统时也一样;用户在两次访问之间改了系统设置才会有一次误差,客户端接管后纠正。

    Nuxt 宿主启用 @xwink/ui/nuxt 即全部接好,不再各写首帧脚本或在 htmlAttrs 里写死档位:

    • head 注入首帧脚本,挂载前按 Cookie 写好 data-theme(全新访客按系统);
    • 客户端插件先于其它插件初始化 useTheme,地址上带宿主 theme 参数(嵌入协议)时改为宿主覆盖;
    • SSR 宿主的服务端插件读 Cookie,把 data-theme 渲染进 HTML,并让本次请求的 useTheme 按该档 计算;渲染用的档位放在 payload 的 UI_SSR_THEME_STATE_KEY 里,挂载前需要与服务端一致的组件按它出。

    不需要接管时 xwinkUi: { theme: false }。

    选项

    选项说明
    storageRef已有的可写来源(如后端偏好接口响应里的 ref);给了它就不碰共享 Cookie
    storageKeynull 表示不持久化;显式给了键而没给 storage 时存 localStorage(不跨站共享)
    storage换掉存储本身(sessionStorage 或自定义实现)
    fallback没有已存偏好时的档位,缺省 auto
    ts
    // 明暗档挂到账号上:值由接口响应驱动,异步到达也会自动生效
    useTheme({ storageRef: preferencesFromApi.themeMode })
    

    单例与调用时机

    内部用 VueUse 的 createSharedComposable + useColorMode:首次调用时的 options 决定整页配置, 之后的调用只是取用。@xwink/ui/nuxt 的插件已在最早时机按缺省配置调过一次,要换存储口的宿主关掉 模块的 theme 接管后在自己的插件里先调。服务端每次调用都是独立实例,不会串请求。

    切换时抑制过渡来自 useColorMode。