antd線上換膚定製功能

taoland發表於2018-09-13

最近react專案,用的antd框架,然後看見他的antdPro例子裡面有個定製功能很帥,老大說做,那就做吧,鼓搗了一晚終於實現了。

先看預覽效果吧

css換膚

入行前端的時候經常看魚哥(張鑫旭)的部落格,記得看過 這篇 ,當時很驚歎,原理其實很簡單,就是我們最能想到的方式,多個css,然後用JS替換從而達到換膚效果。但是這個有侷限性,比如我們用的是antdUI庫,我們不可能每個顏色都去搞個css吧。當時現在我們有less,sass,而且原生的css也有變數var了,所以新時代我們有新技術達到這個效果。

less換膚

其實antd官網是有 定製主題 的,但是是靜態的,通過打包之前去設定一些config,less變數從而達到定製效果,但是這顯然不是我們想要的==線上實時==換膚效果。

最初我的思路是用node去實時生成一個webpack.config.base的配置檔案,但是這樣只能在開發環境實現換膚,生成環境是沒辦法的。然後網上有人說,用less去生成多個css檔案,這不又走了以前的老路嗎。最後沒辦法我把antdPro的原始碼拿來看了下,終於找到了解決辦法,antd-theme-generator

步驟

  • 這裡我的專案是在自己寫的 webpack4-react腳手架 的基礎上做修改的,如果你用的create-react-app或者其他的腳手架可能會有相應修改。
  • 安裝cnpm i antd-theme-generator --save
  • index.html
<body>
    <link rel="stylesheet/less" type="text/css" href="static/color.less" /> //主要是這個起作用
    <script>
        window.less = {
            async: false,
            env: `production`
        };
    </script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script>
    <noscript>
        You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
</body>
  • 根目錄新增color.js
const path = require(`path`);
const { generateTheme, getLessVars } = require(`antd-theme-generator`);

const options = {
  stylesDir: path.join(__dirname, `./src/styles`),    //對應具體位置
  antDir: path.join(__dirname, `./node_modules/antd`), //對應具體位置
  varFile: path.join(__dirname, `./src/styles/vars.less`), //對應具體位置
  mainLessFile: path.join(__dirname, `./src/styles/main.less`), //對應具體位置
  themeVariables: [
    `@primary-color`,
    `@secondary-color`,
    `@text-color`,
    `@text-color-secondary`,
    `@heading-color`,
    `@layout-body-background`,
    `@btn-primary-bg`,
    `@layout-header-background`
  ],
  indexFileName: `index.html`,
  outputFilePath: path.join(__dirname, `./src/static/color.less`),
}

generateTheme(options).then(less => {
  console.log(`Theme generated successfully`);
})
  .catch(error => {
    console.log(`Error`, error);
  });
  • src新增styles資料夾,裡面有vars.less和main.less
//vars.less
@import "~antd/lib/style/themes/default.less";
@link-color: #00375B;
@primary-color: #00375B;
:root { 
    --PC: @primary-color;   //color.less中加入css原生變數:--PC
 }

//main.less
//可為空,只是為了不報錯才引入
  • package.json
//為了每次自動node color.js,所以scripts裡面修改下
"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "dev": "node color &&  webpack-dev-server --config webpack.config.dev.js", 
    "start": "npm run dev",
    "build": "node color && webpack --config webpack.config.prod.js"
  },
  • 使用,啟動後直接window.less.modifyVars就可以了
window.less
    .modifyVars(
        {
            `@primary-color`: `#ee5e7b`,
            `@link-color`: `#ee5e7b`,
            `@btn-primary-bg`: `ee5e7b`,
        }
    )
    .then(() => { })
    .catch(error => {
        message.error(`Failed to update theme`);
    });
  • 最後,打包後注意放入環境後開啟,否則會報錯。

原理

我們發現其實他生效主要就是靠color生成一個color.less檔案,然後我開啟color.less檔案看了下,發現原來是利用的less可以寫邏輯這個特性實現的,從而通過window.less.modifyVars去動態的改變less變數。

其他

現在antd的換膚問題解決了,但是我們自己的css樣式怎麼辦呢,比如我有個標題想用主題色,我怎麼去拿到這個顏色呢。

  • 起初我是這樣實現的vars.less增加
//vars.less
 .primary-color{
     color:@primary-color
 }

這樣.primary-color就會打入生成的color.less裡面,然後我們就可以用了,當時這樣有些地方就不方便,比如box-shadow: 1px 1px 1px 1px #d23333;,我們怎麼辦,難道每次都要寫在vars.less裡面嗎

  • 所以這裡我用了css的原生變數var
//vars.less
:root { 
    --PC: @primary-color;
 }

然後就可以使用box-shadow: 1px 1px 1px 1px var(--PC);

本地儲存

使用者設定顏色後,可以用快取或者localStorage儲存,這就不多說了

預覽效果

原始碼

最後

大家好,這裡是「 TaoLand 」,這個部落格主要用於記錄一個菜鳥程式猿的Growth之路。這也是自己第一次做部落格,希望和大家多多交流,一起成長!文章將會在下列地址同步更新……
個人部落格:www.yangyuetao.cn
小程式:TaoLand


相關文章