【总结】脚手架项目UI适配、动态换肤、代码规范

背景

因为最近对UI规范做了改动,所以需要产出一份和UI规范相适配的脚手架,方便各个项目直接接入,脚手架的话并没有从头开始搞,而是在原来的基础上进行改造,把样式进行修改。效果是这样的:

如果说这个样式改动,直接改其实不难,但我们这个代码不期望直接改原来的,希望两种样式都保留下来,所以添加了一个环境变量来区分,两种UI不同的地方的都会通过环境变量为true来做区分。

环境变量定义:

环境变量使用:process.env.VUE_APP_THEME

具体修改主要做了以下几点:

  1. 特有样式覆盖,通过新增一个css文件,将所有复写的样式集中在一起。
  2. 新增了动态换肤的功能
  3. 添加了代码规范和commit规范

样式覆盖

从两边的样式看,最大的不同是:

  1. header
  2. 左侧menu

而改动其实不难,有几个注意点:

  1. 通过样式覆盖把相关的复写样式抽离到一个文件,例如header背景色,color,
  2. 所有涉及到颜色的都改为css变量 var(xxx)的形式,方便切换主题时自动变化。

还有一个是页面表格的样式,之前的搜索列表搜索区域和列表区域是分开的,而新的是一体的,而表格是根据配置项动态生成的,其实是涉及到一个配置项的修改card:true->card:false,为了不一个个改,所以写了个babel插件,编译时动态修改了配置项来实现。具体如下,其实就判断如果是对象,并且key是card且值是true,则将它的值改为false即可。

js 复制代码
module.exports = function () {
    return {
        visitor: {
            ObjectExpression(path) {
                path.traverse({
                    ObjectProperty(innerPath) {
                        // console.log('innerPath', innerPath.node)
                        if (innerPath.node.key.name === 'card' &&
                            innerPath.node.value.value === true) {
                                // console.log('innerPath  inner', innerPath.node)
                                innerPath.node.value.value = false;
                            } 
                    }
                })
            }
        }
    }
}

以上做完后,会根据process.env.VUE_APP_THEME来动态加载css文件,和这个babel插件。

js 复制代码
// 动态加载UI特有的文件
if (process.env.VUE_APP_THEME === 'true') {
  import('@/utils/loadTheme')
    .then(() => {
      console.log('loadZylcTheme');
    });
}

动态换肤

就是运行时动态切换主题色,用的代码就是 vue-element-admin 这个项目的theme-picker组件

组件核心就是:监听主题色变化,用算法计算出新的颜色的色阶,然后将原来的css文件中的颜色全部替换为新的颜色的色阶。

调色板和色阶

这里涉及到一个调色板的概念,调色板由一系列具有一定代表性的基本色彩及它们的渐变色组成,基本色彩就是主色,其渐变色由色板生成算法计算得到。色板算法比较简单的一种是antDesign发明的tint/shade色彩系统算法,就是在颜色中加入一定比例的黑色或者白色来生成色阶,这个组件使用的就是这种。

例如elementplus官网的默认的主色的色板,主色下面有六个颜色,用于不同状态的颜色设置。。

看官网的源代码,css里就是将主色和白色混合调出--el-color-primary-light-i, 和黑色混合调出了--el-color-primary-dark-2

js 复制代码
// $colors.primary.light-i
// --el-color-primary-light-i
// 10% 53a8ff
// 20% 66b1ff
// 30% 79bbff
// 40% 8cc5ff
// 50% a0cfff
// 60% b3d8ff
// 70% c6e2ff
// 80% d9ecff
// 90% ecf5ff
@each $type in $types {
  @for $i from 1 through 9 {
    @include set-color-mix-level($type, $i, 'light', $color-white);
  }
}

// --el-color-primary-dark-2
@each $type in $types {
  @include set-color-mix-level($type, 2, 'dark', $color-black);
}

// https://sass-lang.com/documentation/values/maps#immutability
// mix colors with white/black to generate light/dark level
@mixin set-color-mix-level(
  $type,
  $number,
  $mode: 'light',
  $mix-color: $color-white
) {
  $colors: map.deep-merge(
    (
      $type: (
        '#{$mode}-#{$number}':
          mix(
            $mix-color,
            map.get($colors, $type, 'base'),
            math.percentage(math.div($number, 10))
          ),
      ),
    ),
    $colors
  ) !global;
}

这个的具体应用就是对于一个按钮,有几种不同的状态,正常态、按压态、不可点,都是不同的颜色,这样就会直接用上面生成的色阶来设置对应的css。

对应关系如下:

知道了色阶的概念后,就知道切换主题时,会根据这个主色算出这个颜色对应的色阶,然后将原有css文件中,所有对应的颜色改成新的颜色即可。当然这里的前提是你的组件的样式都是用的这些css变量定义的颜色,就像elementui的组件库中组件的color大部分都是用的css变量来做的,就是为了方便主题定制。

动态换肤流程

代码theme-picker组件的具体流程就是以下五个步骤:

  1. 监听主题色变化;
  2. 请求默认组件库样式文件,保存在内存,再次切换可以直接使用内存样式;
  3. 根据新的主题色计算色阶10个;
  4. 将默认的文件的颜色都替换为新的色阶;
  5. 项目中style插入的样式也替换为新的色阶

添加代码规范和提交规范

这一块的话,因为项目本身没有,所以把这些都加上了,几件套:eslint、husky、lint-staged、commitlint,很常见的代码规范化工具。

这个地方遇到的一个坑就是,项目的.git目录和.husky目录不是一个目录,那好,不在一个目录的官网也给出了方案:项目不在 Git 根目录 按照这个确实是可以的。

如果问题到这里就结束了也可以皆大欢喜,但是我需要兼容这两种情况。。

解决.git和.husky不在一个目录

因为要兼容两者在一个目录和不在一个目录,所以就得写脚本兼容。脚本的核心就是判断是否在同一个目录,在的话直接安装,不在的话就需要cd到git的目录先安装钩子。

js 复制代码
/**
 * 查找.git目录,
 * 如果在当前目录,则直接执行husky install
 * 如果不在当前目录,则cd到.git的目录, 执行husky install xxx/.husky 安装钩子
 */

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

const GIT_DIR = '.git';
const HUSKY_DIR = '.husky';
const FRONTEND_DIR = path.join('frontend', '.husky');

// 检查目录是否存在
function directoryExists(dir) {
    return fs.existsSync(dir) && fs.lstatSync(dir).isDirectory();
}

function findGitDir() {
    let currentDir = process.cwd();
    while (!directoryExists(path.join(currentDir, GIT_DIR))) {
        const parentDir = path.dirname(currentDir);
        if (parentDir === currentDir) {
            return null;
        }
        currentDir = parentDir;
    }
    return currentDir;
}

function main() {
    const gitDir = findGitDir();
    if (!gitDir) {
        console.log(`cant Found .git directory`);
    }
    console.log(`Found .git directory at: ${gitDir}`);
    const huskyDir = path.join(process.cwd(), HUSKY_DIR);
    const relativeHuskyDir = path.relative(huskyDir, gitDir);
    console.log('relativeHuskyDir', relativeHuskyDir);
   
    if (relativeHuskyDir === '') {
        console.log('.git 和 .husky 在同一个目录,执行安装');
        execSync('husky install', {stdio: 'inherit'});
    } else {
        process.chdir(path.dirname(relativeHuskyDir));
        console.log(`.git 和 .husky 不在同一个目录,切换到git目录执行安装${path.dirname(relativeHuskyDir)}, ${path.dirname(huskyDir)}`);
        execSync(`husky install ${huskyDir}`, { stdio: 'inherit'});
    }
}

main();

到此,husky的安装就兼容完了,还需要修改的就是pre-commit钩子文件的逻辑,也需要判断,如果git和husky在一个目录,则直接执行lint-staged,如果不在,要先cd到husky的目录,再执行命令,这个就是shell脚本了。

shell 复制代码
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

# 脚本执行时目录是git根目录
echo "Current directory: $(pwd)"

HUSKY_DIR='.husky';
FRONTEND_HUSKY_DIR='frontend/.husky';

# 查找并切换到.husky目录
change_to_husky_dir() {
    
    echo "Current directory: $(pwd)"

    if [ -d "$HUSKY_DIR" ]; then
        echo 'Found .husky directory in current directory'
    elif [ -d "$FRONTEND_HUSKY_DIR" ]; then
        echo "Found .husky directory in frontend";
        cd frontend;
    else 
        echo '.husky directory not found in current or frontend directory';
        exit 1
    fi
    return 0
}

if change_to_husky_dir; then
    echo "Current directory: $(pwd)"
    npx lint-staged
else
    exit 1
fi

这样,终于兼容完了!!!

至此,脚手架样式相关的改造就改造完成啦~~

其他

终于写了一篇文章,后续会在接着写,趁着活动撸羊毛。后续文章:

  1. 动态换肤方案
  2. 离线部署的问题,主要是内网部署各自包缺少,真是有点崩溃。

gq不说别的,就环境这点有点受不了,因为物理隔离,包缺的太多,外网导入内网麻烦的要死,还有各种形式主义、效率低下的问题,所以才不太喜欢这里,但是相比互联网,确实要轻松一些,毕竟最近迎着太阳下班,这不就是我想要的吗?

或者要不要离开北京,换个轻松点的城市?

把自己的郁闷情绪写一写,果然能发泄下,好点之后就得继续想下一步怎么办了。

先在新部门好好干一段时间,看看是什么样的,然后2条腿走路,加油吧,生活已经这么难了,自己就得想开点,人只有自己能救自己,只有自己能治愈自己。

相关推荐
阿垚啊14 分钟前
vue属性绑定v-bind
前端·javascript·vue.js
7柒丶19 分钟前
freemarker生成pdf,同时pdf插入页脚,以及数据量大时批量处理
java·前端·pdf
追逐梦想永不停25 分钟前
CSS动画keyframes简单样例
前端·css
赵孝正27 分钟前
python对含数字的列名排序和去重
前端·javascript·python
Ann_R28 分钟前
el-form rules动态限制
前端·javascript·vue.js
SongYuLong的博客31 分钟前
python遍历目录下所有文件
前端·数据库·python
2401_8576226638 分钟前
如何在Laravel中实现数据验证:确保数据准确性的最佳实践
前端·网络·laravel
窗边的anini1 小时前
【前端面经】MiniMax 面试
前端·面试·求职
Simaoya1 小时前
【vue3】 eslint校验关闭未使用变量、组件、单个单词校验
前端·javascript·vue.js
爱学英语的程序员1 小时前
前端面试题 | JavaScript 如何做内存管理?
前端·javascript