angular7主题样式在线切换

参考ng-alain和delon

 思路就是动态加载css文件
代码实现
  1. 写两套less文件,分别为light.less和dark.less

  2. 用相关插件将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');
    
  3. 用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!');
    });
    
  4. 动态切换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();
      }
    
  5. 总代码如下:

    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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值