最近团队正在开发一个组件库,其中遇到一个问题是:在不同业务中使用时,需要根据 UI 定制不同的主题色。
如何实现?
参考 Antd 的主题方案,在构建时,将主题色变量传递给 lessLoader 中 modifyVars 属性,通过 less 变量实现颜色控制。这其中也有很多细节,我们展开聊一下。
首先,我们项目使用 umi 构建,需要配置 .umirc(当然如果你使用 webpack 也基本类似,下面不再特别说明)
// .umirc 配置
const theme = require('./config/share').read('myTheme')
...
const lessLoader = {
modifyVars: {
...theme,
'@base-font-size': '12px',
},
javascriptEnabled: true,
}
export default {
...
lessLoader,
...
}
复制代码
config/share 主要是用于处理主题变量的 less 文件,包括处理文件依赖,相当是一个 plugin:
const lessJs = require('less-vars-to-js')
exports.read = function (fileName) {
const { code } = loadLessWithImports(`src/themes/${fileName}.less`)
return lessJs(code)
}
/*
* 解析 less 文件中依赖的 less 变量,合并输出
*/
function loadLessWithImports(entry) {
const input = readFileSync(entry, 'utf8')
const importRegExp = /^@import\s+['"]([^'"]+)['"];$/gm
// 判断是否有 @import 引入
const imports = getRegexpMatches(importRegExp, input).map((match) => {
const importPath = match[1]
return {
match,
path: importPath,
...loadLessWithImports(importPath),
}
})
return {
code: imports.reduceRight( // imports 数组倒序合并,否则默认的 less 文件变量会将自定义变量覆盖
(acc, { code }) =>
replaceSubstring(acc, code),
input
),
imports: imports.reduce(
(acc, { path, imports: nestedImports }) => [...acc, ...nestedImports, path],
[]
),
}
}
/*
* 获取匹配的 less 文件
*/
function getRegexpMatches(regexp, text) {
var matches = []
var lastIndex = regexp.lastIndex
var match
do {
match = regexp.exec(text)
if (match) {
matches.push(match)
} // prevent infinite loop (only regular expressions with `global` flag retain the `lastIndex`)
} while (match && regexp.global) // don't leak `lastIndex` changes
regexp.lastIndex = lastIndex
return matches
}
复制代码
其中主要方法是 loadLessWithImports,因为整体的思路比较清晰,主要是如何实现文件的解析。它接受 less 文件路径作为参数,并通过正则解析 @import 依赖文件,并递归调用解析。
以上 : )
参考链接
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END