vue2.x element-ui自定義主題 適配css var 變量換膚,真正的自由切換皮膚

B端業(yè)務(wù)中有個需求,不同的客戶需要有自己的主題色, element-ui 官網(wǎng)提供的換膚方式不適用與用戶自定義切換顏色(別問我為什么不升級,你懂得?。脩裟芮袚Q的是內(nèi)置好的,因為客戶很多,不可能內(nèi)置這么多主題。所以決定采用css變量來實現(xiàn)。說干就干~

1. 根據(jù)element-ui官網(wǎng)提供的方案(項目使用的是less,所以使用ele提供的主題工具)

第一步 安裝主題工具和主題(推薦安裝在當(dāng)前項目下)

node環(huán)境 14.20.0


npm i element-theme element-theme-chalk -D


第二步 初始化變量文件

node_modules/.bin/et -i

執(zhí)行后不出意外的話,意外出現(xiàn)了,報錯了。。。開始手忙腳亂, 懷疑是不是姿勢不對,再來一次還是報錯


image.png

在網(wǎng)上沖浪了億會會, 發(fā)現(xiàn)是node版本太高導(dǎo)致的 我使用的是14版本,建議是 11.15以下,解決方案有以下兩種(沖浪的收獲)

 - 安裝低版本 node  11.15以下
 - 安裝 element-themex

我這里用的是第二種方案 安裝 element-themex

image-1.png

安裝成功后再次執(zhí)行 node_modules/.bin/et -i

image-2.png

這次終于成功了,開心~ !我們可以在根目錄下看到 scss 變量文件

image-3.png

第三步 修改變量文件 這里把默認(rèn)色修改為css 變量

image-4.png
/* Color
-------------------------- */
/// color|1|Brand Color|0
$--color-primary: var(--customize-theme) !default;
/// color|1|Background Color|4
$--color-white: #FFFFFF !default;
/// color|1|Background Color|4
$--color-black: #000000 !default;

第四步 執(zhí)行編譯主題命令(坐等主題生成 嗯哼?。?/p>


node_modules/.bin/et

天吶!意外再一次出現(xiàn),報錯了,天塌了!?。?!

image-5.png

報錯提示很明顯,scss mix函數(shù)的入?yún)⑿枰且粋€顏色值。我們傳入一個 css 變量它是不支持的。因為ele主題中一些樣式使用的是默認(rèn)顏色與另外一種混合,根據(jù)一定的比例混合在一起,生成另一種顏色。于是網(wǎng)上沖浪~~無果?。?!
沒辦法業(yè)務(wù)需求要實現(xiàn),頭發(fā)還是需要掉。
經(jīng)過深思熟慮決定解決這個報錯,手動改源碼是不可能的,因為顏色是scss編譯過程生成的,直接改源碼的事就不想聊了~

2.修改 scss 變量的mix函數(shù)

第一步 實現(xiàn) mixToVar 函數(shù)

其實ele提供的主題編譯工具邏輯很簡單,就是把 element-theme-chalk 中的變量暴露出來,供項目修改,修改后再執(zhí)行編譯命令,把修改后的主題文件重寫進(jìn) element-theme-chalk 中的變量文件,在執(zhí)行scss編譯,把scss文件編譯成css文件

那我們也可以加一層命令,就是把 mix 函數(shù)替換掉,替換邏輯很簡單,讀取element-theme-chalk中的scss文件,使用字符串替換就行,函數(shù)名為 mixToVar
mixToVar 入?yún)⑴c mix 函數(shù)一致,這里不用去關(guān)心 mix 函數(shù)的內(nèi)部實現(xiàn)
mixToVar 函數(shù)的需要實現(xiàn)的功能如下

  • 判斷入?yún)⑹欠翊嬖赾ss var 函數(shù)(可以通過scss字符串提供的方法, str-index())
    • 存在var函數(shù)字符串則獲取css變量名 和 其他參數(shù)進(jìn)行拼接 返回新的 var() 函數(shù)
  • 參數(shù)中不存在 var函數(shù) 則直接返回 mix 函數(shù)

mixToVar 具體實現(xiàn)如下 主要使用字符串相關(guān)的操作 判斷索引、截取等

/* 自定義函數(shù) */
@function mixToVar($c1, $c2, $percent: 50%) {

    $str: '';
    $len: str-index($percent + '', '%');
    $percentNew: $percent;

    @if $len {
        $percentNew: str-slice($percent+'', 0, $len - 1)
    }

    $c1Str: $c1+'';
    $c2Str: $c2+'';
    $c1VarIdx: str-index($c1Str, 'var(');
    $c2VarIdx: str-index($c2Str, 'var(');

    @if $c1VarIdx {
        $str: '#{str-slice($c1Str, str-index($c1Str, '(') + 1, str-index($c1Str, ')') - 1)}'
    }

    @else {
        $str: '--YS#{transformColor($c1)}'
    }

    @if $c2VarIdx {
        $c2Var: #{str-slice($c2Str,str-index($c2Str, '(') + 1, str-index($c2Str, ')') - 1)};
        $str: $str + '_#{$c2Var}_' + $percentNew;
        @return var(unquote($str));
    }

    @if $c1VarIdx {
        $str: $str + '_--YS#{transformColor($c2)}_' + $percentNew;
        @return var(unquote($str));
    }

    @return mix($c1, $c2, $percent);
}

@function transformColor($color) {
    $str: $color+'';
    $idx: str-index($str, '#');

    @if $idx {
        @return str-slice($str, $idx+ 1);
    }

    @return $color;
}

// YS 表示顏色值 后續(xù)容易分割字符串
// _ 后續(xù)分割字符使用

// mixToVar 返回示例

// 1
// mixToVar(#409EFF, var(--customize-theme), 60%)
// 返回結(jié)果 var(--YS409EFF_--customize-theme_60)

// 2
// mixToVar(var(--customize-theme), #409EFF, 60%)
// 返回結(jié)果 var(--customize-theme_--YS409EFF_60)

// 3
// mixToVar(var(--customize-theme), var(--customize-theme1), 60%)
// 返回結(jié)果 var(--customize-theme_--customize-theme1_60)

// 4
// mixToVar(#FFFFFF, #409EFF, 10%)
// 返回結(jié)果 #53a8ff

第二步 實現(xiàn)主題工具

函數(shù)已經(jīng)寫好了,后面就是替換mix函數(shù), 為了和ele風(fēng)格保持一致,我這里也簡單實現(xiàn)一個命令行工具(需要一點node基礎(chǔ))ele-theme-tool,工具主要是轉(zhuǎn)換 scss 文件
工具主要功能有下面幾點:

  • 替換mix函數(shù)同時, 注入寫好的 mixToVar 函數(shù)
  • 生成當(dāng)前項目需要用的 主題設(shè)置函數(shù)
    • 主題設(shè)置函數(shù)根據(jù)變量和顏色和比例生成新的顏色

因為變量是動態(tài)生成的變量,項目是無感的,項目不知道工具生成了那些變量,為了傻瓜式,主題工具生成好js方法

工具寫好后發(fā)布,然后安裝工具(項目使用less,scss都可以使用它生成element-ui主題)

npm i ele-theme-tool -D

安裝成功后執(zhí)行以下命令進(jìn)行初始化

  • 執(zhí)行前請確保 element-ui 主題色沒有被定制過,如果定制過重新安裝 element-theme-chalk 再執(zhí)行

  • 如果當(dāng)前根目錄下已經(jīng)存在 element-variables.scss 先刪除再執(zhí)行


node_modules/.bin/ett -i

初始化完成如下圖

image-7.png

我們可以打開 element-variables.scss看一下是否已經(jīng)替換完成,且 mixToVar 函數(shù)是否注入

image-11.png

替換的文件會包含 node_modules/element-theme-chalk 里面的scss文件


image-8.png

再次修改element-variables.scss文件

/* Color
-------------------------- */
/// color|1|Brand Color|0
$--color-primary: var(--customize-theme) !default;
/// color|1|Background Color|4
$--color-white: #FFFFFF !default;
/// color|1|Background Color|4
$--color-black: #000000 !default;

第三步 執(zhí)行element-ui提供的 主題編譯方法 注意是 element-ui 提供的方法


node_modules/.bin/et

這一次沒有出現(xiàn)意外,成功了?。。。。。。。?!趾高氣昂!?。?!

image-9.png

打開生成的主題文件夾theme下的css文件可以看到,替換好的 css var函數(shù)

image-10.png

第四步 獲取變量,并生產(chǎn)主題設(shè)置工具

雖然顏色值已經(jīng)替換完成,但是可以發(fā)現(xiàn)都是一些顏色和變量組成的新變量,無法閱讀,也沒法在外面設(shè)置,所以工具的另外一個作用就是生成一個工具函數(shù),供外部項目使用

執(zhí)行ele-theme-tool 提供的命令


node_modules/.bin/ett -s

這個命令其實還有設(shè)置默認(rèn)顏色(#409EFF)的功能,顏色設(shè)置沒有暴露出來,有興趣的自己實現(xiàn)下

執(zhí)行完后可以看到css 文件已經(jīng)修改

image-12.png

項目引入編譯好的主題


import "../theme/index.css";

運行項目可以發(fā)現(xiàn)主題已經(jīng)修改為默認(rèn)的主題色 #409EFF

image-13.png

那如何動態(tài)修改呢?執(zhí)行完命令后,項目根路徑下多了一個 theme-tool-web.js 文件, 在項目中使用它

image-15.png

刷新頁面可以看到,顏色值已經(jīng)修改為設(shè)置的顏色

image-14.png

使用 ColorPicker 顏色選擇器,直接切換顏色,也可以正常執(zhí)行

image-16.png
如果使用中遇到node版本等問題可以初始化一個新的空項目,使用指定的node版本,定義完主題后,把主題文件夾和theme-tool-web.js 文件復(fù)制到實際項目中引用(element-ui 提供的自定義工具,其實就是生成了一個 css 目錄)

ele-theme-tool 也可以直接通過js調(diào)用方式工作
例如根據(jù)element-ui二次封裝的組件庫可以使用此方式換膚, 這里就不在贅述,有需求,可以根據(jù)源碼改造、封裝

const { init, build, varUtil } = require('ele-theme-tool')

 init.themeInit({
    targetThemePathRoot,
    themeDir,
    themeVarName,
    themeVarPath,
    message: '初始化主題變量'
})

build.themeBuild({
    targetThemePathRoot,
    targetFontsRoot,
    themeDir,
    targetThemeVarPath,
    minimize: true,
    out: themeOutDir, 
    themeVarPath: path.resolve('variables.scss')
},() => {
    varUtil.setDefaultVarColor({
        themeDir:themeOutDir
    })
})

github地址: ele-theme-tool

總結(jié):可以愉快的自定義主題了,如果需要兼容低版本瀏覽器,建議考慮其他方案或者使用css-vars-ponyfill適配

頭發(fā)沒了。。。,有更好的方案,可以再評論區(qū)分享下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容