You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在运行时切换Storybook v7文档主题?

解决Storybook v7文档主题运行时切换问题

问题核心

你当前的实现仅修改了组件自身的主题类和静态的docs.theme参数,但preview.ts中的parameters是初始化时固定的,运行时修改不会触发文档主题更新;而manager.ts通过addons.setConfig可以动态更新UI主题(侧边栏、工具栏等),但文档内容的主题需要单独处理。

解决方案

需要同步更新UI主题和文档内容主题,利用Storybook的全局变量和通道通信实现动态切换:

1. 修改preview.ts实现文档主题动态更新
import type { Preview } from '@storybook/vue3';
import { themes } from '@storybook/theming';
import { addons } from '@storybook/preview-api';
import { UPDATE_GLOBALS } from '@storybook/core-events';

import '../src/theme/index.scss';
import '../src/theme/themes.scss';

// 统一主题切换逻辑
const switchTheme = (themeName: 'light' | 'dark') => {
  // 切换组件自身主题类
  const htmlEl = document.getElementsByTagName('html')[0];
  htmlEl.classList.remove('light', 'dark');
  htmlEl.classList.add(themeName);

  // 保存主题到本地存储
  const targetTheme = themeName === 'light' ? themes.light : themes.dark;
  localStorage.setItem('theme', JSON.stringify(targetTheme));

  // 更新全局文档主题变量
  addons.getChannel().emit(UPDATE_GLOBALS, {
    globals: { docsTheme: targetTheme },
  });

  // 通知manager切换UI主题
  addons.getChannel().emit('syncUiTheme', targetTheme);

  // 强制重新渲染故事和文档
  addons.getChannel().emit('FORCE_RE_RENDER');
};

// 初始化主题
const savedTheme = JSON.parse(localStorage.getItem('theme') || JSON.stringify(themes.light));
const initialTheme = savedTheme === themes.light ? 'light' : 'dark';
switchTheme(initialTheme);

const preview: Preview = {
  parameters: {
    layout: 'centered',
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
    docs: { theme: savedTheme }, // 初始化文档主题
  },
  // 定义全局变量用于动态更新文档主题
  globals: { docsTheme: savedTheme },
  // 监听全局变量变化,同步更新文档参数
  globalTypes: {
    docsTheme: {
      name: 'Docs Theme',
      description: '切换文档内容主题',
      defaultValue: savedTheme,
      onChange: (newTheme) => {
        addons.getChannel().emit('updateParameters', {
          docs: { theme: newTheme },
        });
      },
    },
  },
};

// 测试延迟切换(实际项目替换为工具栏按钮/交互触发)
setTimeout(() => switchTheme('dark'), 4000);

export default preview;
2. 修改manager.ts同步UI主题
import { addons } from '@storybook/manager-api';
import { themes } from '@storybook/theming';
import { addons as previewAddons } from '@storybook/preview-api';

// 初始化UI主题
const savedTheme = JSON.parse(localStorage.getItem('theme') || JSON.stringify(themes.light));
addons.setConfig({ theme: savedTheme });

// 监听preview的主题同步事件
previewAddons.getChannel().on('syncUiTheme', (theme) => {
  addons.setConfig({ theme });
});

关键原理说明

  • 全局变量(globals):通过定义docsTheme全局变量,实现运行时动态传递主题配置。
  • 通道通信(Channel):在preview和manager之间建立通信,确保UI主题与文档主题同步切换。
  • 动态参数更新:通过updateParameters事件修改docs.theme参数,触发文档内容重新渲染主题样式。

注意事项

  • 确保@storybook/theming版本与Storybook核心版本一致,避免主题对象不兼容。
  • 若使用自定义MDX文档样式,需基于light/dark类做适配,确保样式随主题切换。

内容的提问来源于stack exchange,提问作者therabbityouknow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 11:38:20