参考链接:cloud.tencent.com/developer/a…
思路:利用postcss的相关插件能力来实现
用vue-cli创建的vue2项目
vue-cli的版本:@vue/cli 5.0.8
根据文章中描述,分别创建了index.css测试文件、vue.config.js(项目创建时,自动创建)、postcss插件,几个文件的具体内容如下:
/* index.css文件 */
* {
color: rgb(197, 153, 153);
}
div {
color: cc(G01);
display: flex;
}
.hello {
border: 1px solid cc(G01);
}
// postcss-theme.js
const defaults = {
function: 'cc',
groups: {},
colors: {},
useCustomProperties: false,
darkThemeSelector: 'html[data-theme="dark"]',
nestingPlugin: null,
}
const resolveColor = (options, theme, group, defaultValue) => {
const [lightColor, darkColor] = options.groups[group] || []
const color = theme === 'dark' ? darkColor : lightColor
if (!color) {
return defaultValue
}
if (options.useCustomProperties) {
return color.startsWith('--') ? 'var(${color})' : 'var(--${color})'
}
return options.colors[color] || defaultValue
}
/**
* @type {import('postcss').PluginCreator}
*/
module.exports = (options = {}) => {
// Work with options here
options = Object.assign({}, defaults, options)
// 获取色值函数(默认为cc)
const reGroup = new RegExp(`\\b${options.function}\\(([^)]+)\\)`, 'g')
// 获取最终的CSS值
const getValue = (value, theme) => {
return value.replace(reGroup, (match, group) => {
return resolveColor(options, theme, group, match)
})
}
return {
postcssPlugin: 'postcss-theme-colors',
prepare(result){
const hasPlugin = name => name.replace(/^postcss-/, '') === options.nestingPlugin || result.processor.plugins.some(p => p.postcssPlugin === name)
return {
Declaration (decl, postcss) {
// The faster way to find Declaration node
const value = decl.value
// 如果不含有色值函数调用,则提前退出
if (!value || !reGroup.test(value)) {
return
}
const lightValue = getValue(value, 'light')
const darkValue = getValue(value, 'dark')
const darkDecl = decl.clone({ value: darkValue })
let darkRule
// 使用插件,生成Dark主题模式
if (hasPlugin('postcss-nesting')) {
darkRule = postcss.atRule({
name: 'nest',
params: `${options.darkThemeSelector} &`,
})
} else if (hasPlugin('postcss-nested')) {
darkRule = postcss.rule({
selector: `${options.darkThemeSelector} &`,
})
} else {
decl.warn(result, 'Plugin(postcss-nesting or postcss-nested) not found')
}
console.log('darkDecl:', darkDecl)
// 添加Dark主题模式到目标HTML根节点中
if (darkRule) {
darkRule.append(darkDecl)
decl.after(darkRule)
}
const lightDecl = decl.clone({ value: lightValue })
decl.replaceWith(lightDecl)
}
}
}
/*
Root (root, postcss) {
// Transform CSS AST here
}
*/
/*
Declaration: {
color: (decl, postcss) {
// The fastest way find Declaration node if you know property name
}
}
*/
}
}
module.exports.postcss = true
这里主要的实现方式与文章中的实现方式一致,只是代码结构会有点差别。用文章中那种方式的时候,控制台提示此种方式已经被废弃了,然后再查看了一下
postcss的官网后,使用的插件模板也是用的本文中的方式。postcss官网:postcss.org/docs/writin…
// vue.config.js
const { defineConfig } = require('@vue/cli-service')
const postcssTheme = require('./plugins/postcss-theme')
module.exports = defineConfig({
transpileDependencies: true,
css: {
loaderOptions: {
postcss: {
postcssOptions: {
plugins: [
{
// 用这个插件,主要是因为此插件内置了`autoprefixer、postcss-nesting/postcss-nested、postcss-importautoprefixer、postcss-nesting/postcss-nested、postcss-import`,
// 我们在自定义插件内部使用了hasPlugin('postcss-nesting')和hasPlugin('postcss-nested'),实际使用中可能需要微调
"postcss-preset-env": {
features: {
"custom-properties": {
preserve: false,
variables: {}
},
"nesting-rules": true
}
},
},
postcssTheme({
colors: {
c01: '#333',
c02: '#111'
},
groups: {
G01: ['c01', 'c02']
}
})
]
}
}
}
}
})
在验证插件在vue项目中使用时,出现报错,# object Object is not a PostCSS plugin,出错的原因猜测是
postcss-preset-env版本与postcss版本不匹配,但是重新更新这两个包的版本后,还是报错。后来用脚手架重新建了一个vue2的项目后,不会再出问题
自建的项目,打包工具为webpack
这里的区别与上一节的区别是使用postcss.config.js来代替vue.config.js,具体代码为:
//postcss.config.js
const postcssTheme = require('./plugins/postcss-theme')
module.exports = {
plugins: [
{
"postcss-preset-env": {
features: {
"custom-properties": {
preserve: false,
variables: {}
},
"nesting-rules": true
}
},
},
postcssTheme({
colors: {
c01: '#222',
c02: '#111'
},
groups: {
G01: ['c01', 'c02']
}
})
]
}