背景
因为最近对UI规范做了改动,所以需要产出一份和UI规范相适配的脚手架,方便各个项目直接接入,脚手架的话并没有从头开始搞,而是在原来的基础上进行改造,把样式进行修改。效果是这样的:
如果说这个样式改动,直接改其实不难,但我们这个代码不期望直接改原来的,希望两种样式都保留下来,所以添加了一个环境变量来区分,两种UI不同的地方的都会通过环境变量为true来做区分。
环境变量定义:
环境变量使用:process.env.VUE_APP_THEME
具体修改主要做了以下几点:
- 特有样式覆盖,通过新增一个css文件,将所有复写的样式集中在一起。
- 新增了动态换肤的功能
- 添加了代码规范和commit规范
样式覆盖
从两边的样式看,最大的不同是:
- header
- 左侧menu
而改动其实不难,有几个注意点:
- 通过样式覆盖把相关的复写样式抽离到一个文件,例如header背景色,color,
- 所有涉及到颜色的都改为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组件的具体流程就是以下五个步骤:
- 监听主题色变化;
- 请求默认组件库样式文件,保存在内存,再次切换可以直接使用内存样式;
- 根据新的主题色计算色阶10个;
- 将默认的文件的颜色都替换为新的色阶;
- 项目中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
这样,终于兼容完了!!!
至此,脚手架样式相关的改造就改造完成啦~~
其他
终于写了一篇文章,后续会在接着写,趁着活动撸羊毛。后续文章:
- 动态换肤方案
- 离线部署的问题,主要是内网部署各自包缺少,真是有点崩溃。
gq不说别的,就环境这点有点受不了,因为物理隔离,包缺的太多,外网导入内网麻烦的要死,还有各种形式主义、效率低下的问题,所以才不太喜欢这里,但是相比互联网,确实要轻松一些,毕竟最近迎着太阳下班,这不就是我想要的吗?
或者要不要离开北京,换个轻松点的城市?
把自己的郁闷情绪写一写,果然能发泄下,好点之后就得继续想下一步怎么办了。
先在新部门好好干一段时间,看看是什么样的,然后2条腿走路,加油吧,生活已经这么难了,自己就得想开点,人只有自己能救自己,只有自己能治愈自己。