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
相关产品推荐
相关产品推荐

