参考ng-alain和delon
思路就是动态加载css文件
代码实现
-
写两套less文件,分别为light.less和dark.less
-
用相关插件将less文件转为一个js对象(less-vars-to-js 插件)
function genToJs(type) { const ngZorroAntdStylePath = path.join(__dirname, '../node_modules/ng-zorro-antd/style'); const ngZorro = ` ${fs.readFileSync(path.join(ngZorroAntdStylePath, 'color', 'colors.less'), 'utf8')} ${fs.readFileSync(path.join(ngZorroAntdStylePath, 'themes', `default.less`), 'utf8')} `; const packagesPath = path.join(__dirname, '../src/styles'); const ngAlain = ` ${fs.readFileSync(path.join(packagesPath, `${type}.less`), 'utf8')} `; return lessToJs(`${ngZorro}${ngAlain}`, { stripPrefix: true, resolveVariables: false, }); } const darkThemeVars = genToJs('dark'); const lightThemeVars = genToJs('light');
-
用less插件修改modifyVars中的变量,根据主题来切换生成的对象,然后导出成css文件
function gen(type) { return less .render(themeContent, { javascriptEnabled: true, plugins: [ new LessPluginNpmImport({ prefix: '~' }), new LessPluginCleanCSS({ advanced: true }) ], modifyVars: { ...(type === 'dark' ? darkThemeVars : lightThemeVars), }, }) .then((data) => { fs.writeFileSync( // 主题样式的输出文件 `src/assets/style.${type}.css`, data.css, ); }) .catch((e) => { // 记录渲染错误 console.error(type, e); }); } Promise.all([gen('dark'), gen('light')]).then(() => { console.log('Success!'); });
-
动态切换css文件
onThemeChange(theme: SiteTheme): void { if (!this.platform.isBrowser) { return; } this.theme = theme; const dom = document.getElementById('site-theme'); if (dom) { dom.remove(); } localStorage.removeItem('site-theme'); if (theme !== 'default') { const el = (this.el = document.createElement('link')); el.type = 'text/css'; el.rel = 'stylesheet'; el.id = 'site-theme'; el.href = `assets/style.${theme}.css`; localStorage.setItem('site-theme', theme); document.body.append(el); } this.updateChartTheme(); }
-
总代码如下:
const less = require('less'); const LessPluginCleanCSS = require('less-plugin-clean-css'); const LessPluginNpmImport = require('less-plugin-npm-import'); const fs = require('fs'); const path = require('path'); const lessToJs = require('less-vars-to-js'); // const darkThemeVars = require('@delon/theme/theme-dark'); // const compactThemeVars = require('@delon/theme/theme-compact'); const appStyles = 'src/styles.less'; // 应用的样式入口文件 const themeContent = `@import '${appStyles}';`; // 根据参数来将less文件生成对应的js对象 function genToJs(type) { const ngZorroAntdStylePath = path.join(__dirname, '../node_modules/ng-zorro-antd/style'); const ngZorro = ` ${fs.readFileSync(path.join(ngZorroAntdStylePath, 'color', 'colors.less'), 'utf8')} ${fs.readFileSync(path.join(ngZorroAntdStylePath, 'themes', `default.less`), 'utf8')} `; const packagesPath = path.join(__dirname, '../src/styles'); const ngAlain = ` ${fs.readFileSync(path.join(packagesPath, `${type}.less`), 'utf8')} `; return lessToJs(`${ngZorro}${ngAlain}`, { stripPrefix: true, resolveVariables: false, }); } const darkThemeVars = genToJs('dark'); const lightThemeVars = genToJs('light'); // 根据参数来生成对应的css文件 function gen(type) { return less .render(themeContent, { javascriptEnabled: true, plugins: [new LessPluginNpmImport({ prefix: '~' }), new LessPluginCleanCSS({ advanced: true })], modifyVars: { ...(type === 'dark' ? darkThemeVars : lightThemeVars), }, }) .then((data) => { fs.writeFileSync( // 主题样式的输出文件 `src/assets/style.${type}.css`, data.css, ); }) .catch((e) => { // 记录渲染错误 console.error(type, e); }); } Promise.all([gen('dark'), gen('light')]).then(() => { console.log('Success!'); });
参考:
delon: https://github.com/ng-alain/delon/blob/9.x/scripts/build/vars.js#L7-L33.
ng-alalin: https://github.com/ng-alain/ng-alain/blob/9.x/scripts/theme.js#L10-L34.
补充
- 切换完样式下拉框、提示信息有问题,不正常显示
- 原因: dropdown和tooltip组件等样式在组件中写的
.ant-dropdown-menu,
.ant-select-dropdown,
.ant-mention-dropdown,
.ant-dropdown,
.ant-cascader-menus {
top : 100%;
left : 0;
position : relative;
width : 100%;
margin-top : 4px;
margin-bottom: 4px;
}
.ant-tooltip{
position : relative;
}