element-plus主题定制

2,385 阅读2分钟

前天B站有位博主推荐Nextuinextui.org ,我去它的网站看了一下,确实挺好看的。可惜这个组件库只支持React。
别的组件还行吧,对我影响最深刻的是它的主题色,然后我想,element-plus的主题色也能不能改成跟它一样呢,答案是当然可以的,element-plus官方也提供了更改主题的的教程。

1.全部导入主题定制

为什么叫全部导入主题定制呢,是因为element-plus的css样式也是支持按需导入的,但是这里我进行了全部导入。
1.创建vue项目(我是通过pnpm create vite创建的
2.安装element-plus(请自行安装)
3.安装tailwindcss环境(请自行安装)
4.项目文件结构:

image.png 有些文件我进行了隐藏,比如.gitignore。
main.js:

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import './styles/index.scss'
import App from './App.vue'

const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')

elplus-reset.scss自定义样式文件:

@forward 'element-plus/theme-chalk/src/common/var.scss' with (
  // 自定义主题颜色
  $colors: (
    'primary': (
      'base': #006FEE, // 将主题色修改为橙色
    ),
    'success': (
    'base': #17c964,
    ),
    'warning':(
    'base': #f5a524,
    ),
    'danger': (
    'base': #f31260,
    ),
    'error': (
    'base': #f31260,
    ),
    // inf保持element plus默认的颜色
  ),

  // 重置element-plus字体大小
  $font-size: (
  'extra-large': 22px,
  'large': 20px,
  'medium': 18px,
  'base': 16px,
  'small': 14px,
  'extra-small': 13px,
  )
);

我们通过@forward导入了element-plus的var.scss,并用with修改var.scss中的某些变量后,暴露出去了,@forward的功能就是导入某一个某块,并且把这个某块暴露出去。

with 用来对导入的模块进行修改,我们用with来修改了element-plus的var.scss中的某些变量,比如,我们对颜色变量$colors进行了修改,但是我们没有对颜色info进行修改,这个颜色会保持element-plus的默认颜色。

我们可以这样理解,如果我们用@forward with来进行修改,修改的是我们在elplus-reset.scss中写的内容,如果在这里不写,会保持element-plus默认的样式。

我这里定义的颜色分别对应nextui中的主题颜色:

image.png

index.scss:

@use "elplus-reset.scss" as *;  // 引入自定义变量

/* 
 使用 SCSS 源文件,注意,一定要引入scss文件
 不要引入import 'element-plus/dist/index.css'
 因为css文件是编译以后的文件,如果导入的是css文件
 主题定制不生效!
 */
@use "element-plus/theme-chalk/src/index.scss" as *;
@tailwind base;
@tailwind components;
@tailwind utilities;

html {
  font-size: 16px;
}

注意一下导入顺序,先导入我们自定义样式的scss文件,然后导入element-plus的scss文件。因为 Element Plus 的样式文件会根据这些变量生成相应的样式。
在App.vue中进行测试:

<template>
  <div class="w-48 mx-auto mt-20">
    <el-button type="success">按钮</el-button>
  </div>
</template>

image.png type="primary":

image.png type="danger":

image.png 通过tailwindcss类名修改按钮的样式(注意index.scss的导入顺序,否则类名可能不会生效):

<template>
  <div class="w-48 mx-auto mt-20">
    <el-button 
        type="primary"
        plain size="large"
        class="font-semibold rounded-lg"
    >
      按钮
    </el-button>
  </div>
</template>

效果图:

image.png 具体想修改什么样式,可以从element-plus/theme-chalk/src/common/var.scss里找到,比如下面是element-plus官方定义的button的样式:

image.png 又比如字体大小:

image.png 找这些变量比较麻烦,所以善用ctrl + F😁
element-plus最让人头疼的时修改默认样式,现在感觉这个问题也解决了😁

2.全部导入主题定制的弊端

这样主题定制虽然比较简单,但是打包以后的css文件比较大,比如,我页面中没怎么写css样式,打包以后的css文件体积足足有350kb大。

3.按需导入主题定制

首先参考element-plus官方文档,配置按需引入组件:

pnpm add -D unplugin-vue-components unplugin-auto-import unplugin-element-plus

注意,这里多了unplugin-element-plus
vite.config.js进行配置:

import { fileURLToPath, URL } from 'node:url' // 用于指定路径别名
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import ElementPlus from 'unplugin-element-plus/vite'

export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver({ importStyle: 'sass'})],   // 按需导入组件和样式
    }),
    ElementPlus({
      useSource: true,  // 使用 SCSS 源文件
    }),
  ],

  // 指定@指向src
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },

  // 引入自定义样式文件
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "@/styles/elplus-reset.scss" as *;`,
      },
    },
  },
})

main.js中不用导入element-plus的组件或者css文件,因为我们配置了按需导入:

import { createApp } from 'vue'
import './styles/index.scss'
import App from './App.vue'

const app = createApp(App)
app.mount('#app')

elplus-reset.scss:

@forward 'element-plus/theme-chalk/src/common/var.scss' with (
  // 自定义主题颜色
  $colors: (
    'primary': (
      'base': #006FEE, // 将主题色修改为橙色
    ),
    'success': (
    'base': #17c964,
    ),
    'warning':(
    'base': #f5a524,
    ),
    'danger': (
    'base': #f31260,
    ),
    'error': (
    'base': #f31260,
    ),
    // inf保持element plus默认的颜色
  ),

  // 重置element-plus字体大小
  $font-size: (
  'extra-large': 22px,
  'large': 20px,
  'medium': 18px,
  'base': 16px,
  'small': 14px,
  'extra-small': 13px,
  )
);

index.scss:

@tailwind base;
@tailwind components;
@tailwind utilities;

html {
  font-size: 16px;
}

注意:这里不需要引入elplus-reset.scss,因为我们已经在vite.config.js中指定了导入该文件。

在组件中使用:

<template>
  <div class="w-48 mx-auto mt-20">
    <el-button
        type="primary"
        plain size="large"
        class="!font-semibold !rounded-lg"
    >
      按钮
    </el-button>
  </div>
</template>

因为我们进行了element-plus组件和样式的按需导入,所以tailwindcss类名的优先级还不够,所以需要这样写!font-semibold !rounded-lg才能覆盖element-plus默认的样式。
效果图:

image.png

image.png

image.png 打包以后css文件大小:

image.png 确实实现了样式和组件的按需导入。

4.按需导入主题定制的弊端

弊端就是,tailwindcss的样式的优先级不够,所以经常在类名前面加上!。哎,没办法🫡

5.扩展

下面代码中,我自定义了button和tag的样式:

@forward 'element-plus/theme-chalk/src/common/var.scss' with (
  // 自定义主题颜色
  $colors: (
    'primary': (
      'base': #006FEE, // 将主题色修改为橙色
    ),
    'success': (
    'base': #17c964,
    ),
    'warning':(
    'base': #f5a524,
    ),
    'danger': (
    'base': #f31260,
    ),
    'error': (
    'base': #f31260,
    ),
    // inf保持element plus默认的颜色
  ),

  // 重置element-plus字体大小
  $font-size: (
  'extra-large': 22px,
  'large': 20px,
  'medium': 18px,
  'base': 16px,
  'small': 14px,
  'extra-small': 13px,
  ),

  // 重置按钮字体大小
  $button: (
  'font-weight': 600
  ),
  $button-border-radius: (
  'large': 8px,
  'default': 8px,
  'small': 6px,
  ),

  // 重置tag的样式
  $tag: (
  'font-size': 16px,
  'border-radius': 8px,
  )
);

.el-tag {
  font-weight: 600;
}

在组件中使用:

<template>
  <div class="max-w-lg mx-auto mt-20">
    <el-button
        type="warning"
        plain size="large"
        class="m-4"
    >
      按钮
    </el-button>
    <el-button
        type="primary"
        plain size="large"
        class="m-4"
    >
      按钮
    </el-button>
    <el-button
        type="success"
        plain size="large"
        class="m-4"
    >
      按钮
    </el-button>
    <el-button
        type="danger"
        plain size="large"
        class="m-4"
    >
      按钮
    </el-button>
    <el-button
        type="info"
        plain size="large"
        class="m-4"
    >
      按钮
    </el-button>

    <el-tag size="large" class="mr-4">Vue</el-tag>
    <el-tag type="success" size="large" class="m-4">Vue</el-tag>
    <el-tag type="warning" size="large" class="m-4">Vue</el-tag>
    <el-tag type="danger" size="large" class="m-4">Vue</el-tag>
    <el-tag type="info" size="large" class="m-4">Vue</el-tag>
  </div>
</template>
<script setup lang="ts">
</script>

效果图:

image.png

image.png