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

Angular Storybook中如何为单个Story加载指定SCSS文件?

解决Storybook 7 + Angular 17多品牌样式冲突问题

针对你遇到的多品牌样式在Storybook中全局加载冲突的问题,以下是几种实用的解决方案:

方案1:强化现有包装组件的样式隔离

你的包装组件思路可行,可通过显式指定Shadow DOM封装来提升隔离效果,避免样式泄漏:

import { Component, ViewEncapsulation } from "@angular/core";

@Component({
    selector: "typography-wrapper",
    styleUrls: ["./typography-wrapper.styles.scss"],
    template:`<ng-content></ng-content>`,
    // 启用Shadow DOM完全隔离样式
    encapsulation: ViewEncapsulation.ShadowDom
})
export class TypographyWrapper {}

@Component({
    selector: "typography-v2-wrapper",
    styleUrls: ["./typography-v2-wrapper.styles.scss"],
    template:`<ng-content></ng-content>`,
    encapsulation: ViewEncapsulation.ShadowDom
})
export class TypographyV2Wrapper {}

Shadow DOM会将组件样式完全包裹在独立的DOM树中,彻底避免不同品牌样式互相干扰。

方案2:通过Storybook全局参数实现品牌动态切换

无需维护多个包装组件,利用Storybook的全局参数和装饰器,实现品牌样式的按需加载:

步骤1:配置全局品牌参数

在.storybook/preview.ts中添加品牌切换的全局配置:

import { Preview } from "@storybook/angular";

const preview: Preview = {
  globals: {
    brand: {
      defaultValue: "brand1",
      toolbar: {
        icon: "paintbrush",
        items: [
          { value: "brand1", title: "品牌1" },
          { value: "brand2", title: "品牌2" },
        ],
      },
    },
  },
};

export default preview;

步骤2:编写品牌样式切换装饰器

创建.storybook/decorators/brandDecorator.ts:

export const brandDecorator = (story, context) => {
  const currentBrand = context.globals.brand;
  
  // 移除旧品牌样式
  const oldStyleLink = document.querySelector(`link[data-brand]`);
  oldStyleLink?.remove();

  // 加载当前品牌样式
  const newStyleLink = document.createElement('link');
  newStyleLink.setAttribute('rel', 'stylesheet');
  newStyleLink.setAttribute('data-brand', currentBrand);
  // 替换为你的编译后样式路径
  newStyleLink.setAttribute('href', `../styles/${currentBrand}/components/type.css`);
  document.head.appendChild(newStyleLink);

  return story();
};

步骤3:注册装饰器

在.storybook/preview.ts中引入并注册装饰器:

import { Preview } from "@storybook/angular";
import { brandDecorator } from './decorators/brandDecorator';

const preview: Preview = {
  // ... 原有配置
  decorators: [brandDecorator],
};

export default preview;

完成后,你可以通过Storybook工具栏的品牌切换按钮,动态加载对应品牌的样式,避免全局冲突。

方案3:用CSS变量统一管理品牌差异

将品牌样式差异抽离为CSS变量,通过切换变量值实现品牌样式切换,无需维护多套样式文件:

步骤1:定义品牌变量文件

// styles/brand1/variables.scss
:root {
  --text-primary: #2d3748;
  --text-secondary: #4a5568;
  --font-size-heading: 2rem;
}
// styles/brand2/variables.scss
:root {
  --text-primary: #1a202c;
  --text-secondary: #2d3748;
  --font-size-heading: 2.2rem;
}

步骤2:组件样式使用变量

// components/typography/typography.scss
.heading {
  color: var(--text-primary);
  font-size: var(--font-size-heading);
}

步骤3:Storybook中切换变量

编写装饰器动态替换全局变量:

// .storybook/decorators/brandVarDecorator.ts
export const brandVarDecorator = (story, context) => {
  const brand = context.globals.brand;
  const oldStyle = document.querySelector(`style[data-brand-vars]`);
  oldStyle?.remove();

  const newStyle = document.createElement('style');
  newStyle.setAttribute('data-brand-vars', brand);
  
  if (brand === 'brand1') {
    newStyle.textContent = `
      :root {
        --text-primary: #2d3748;
        --text-secondary: #4a5568;
        --font-size-heading: 2rem;
      }
    `;
  } else if (brand === 'brand2') {
    newStyle.textContent = `
      :root {
        --text-primary: #1a202c;
        --text-secondary: #2d3748;
        --font-size-heading: 2.2rem;
      }
    `;
  }
  
  document.head.appendChild(newStyle);
  return story();
};

最后在preview.ts中注册该装饰器即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 07:42:54