Angular组件通过不同CSS样式表动态切换主题时if判断不生效问题
问题根因
你遇到的现象是Angular构建时的编译限制导致的,和你写的if判断逻辑没有关系。
Angular的@Component装饰器里的所有元数据(包括styleUrls、templateUrl这些属性)都是在构建编译阶段就会被Angular编译器处理的,scss文件会在这个阶段被编译成css、打包进最终的产物,不会等到运行时再去读取你动态赋值的stylePath变量。你看到的“先写的主题永远生效”,本质是编译阶段编译器直接取了变量初始化的第一个值做打包,运行时的变量修改根本不会影响已经编译好的样式资源。
可行实现方案
你当前的单主题文件打包、切换后重载页面的逻辑不需要做大幅调整,按以下步骤修改即可实现需求:
第一步:调整主题文件的打包配置
把所有主题scss文件在angular.json里配置成独立的构建产物,不要和组件绑定:
打开angular.json,找到projects -> 你的项目名 -> architect -> build -> options -> styles节点,按如下格式配置:
"styles": [ "src/styles.scss", { "input": "src/app/app.component_theme1.scss", "bundleName": "theme1", "inject": false }, { "input": "src/app/app.component_theme2.scss", "bundleName": "theme2", "inject": false } ]
inject: false是告诉Angular构建时不要自动把这些样式注入到index.html里,bundleName是打包后生成的css文件名,构建后会在dist目录下生成theme1.css、theme2.css两个独立文件。
第二步:运行时动态加载样式
删掉@Component里的styleUrls配置,在app.component.ts的ngOnInit生命周期里读取localStorage的主题配置,动态创建link标签加载对应样式:
ngOnInit() { // 读取本地存储的主题配置 const settingsString = localStorage.getItem('usergraphicsdata'); let themeName = 'theme1'; // 配置默认主题 let graphicFolder = '/assets/theme1/'; if (settingsString) { const myUserSettings = JSON.parse(settingsString); themeName = myUserSettings.theme || 'theme1'; graphicFolder = `/assets/${themeName}/`; } // 动态插入样式标签 const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = `${themeName}.css`; document.head.appendChild(link); }
第三步:适配切换逻辑
你原有的切换后重载页面的逻辑无需修改,切换时把新的主题名存到localStorage之后调用window.location.reload()重载即可,重载后会自动加载对应主题的样式文件。如果后续不需要重载页面,也可以在切换时找到已插入的link标签,直接修改href属性为新的主题css路径即可即时生效。
内容的提问来源于stack exchange,提问作者PelPhp

