# 自定义主题

基于vue3+element-ui-plus组合

# 1. 创建主题配置文件

首先,在项目的 src/styles/ 目录下创建 element/index.scss 文件:

// src/styles/element/index.scss
/* 自定义Element Plus主题 */
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
  $colors: (
    'primary': (
      'base': #4a90e2,
    ),
    'success': (
      'base': #67c23a,
    ),
    'warning': (
      'base': #e6a23c,
    ),
    'danger': (
      'base': #f56c6c,
    ),
    'error': (
      'base': #f56c6c,
    ),
    'info': (
      'base': #909399,
    ),
  ),
  
  // 可选:调整组件尺寸变量
  $button-padding-horizontal: (
    'default': 40px
  )
);

# 2. 配置 Vite

接下来,修改 vite.config.ts 文件,确保SCSS变量正确加载:

// vite.config.ts
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'

export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [ElementPlusResolver({
        importStyle: 'sass' // 关键配置
      })],
    }),
    Components({
      resolvers: [ElementPlusResolver({
        importStyle: 'sass' // 关键配置
      })],
    }),
  ],
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "@/styles/element/index.scss" as *;` // 关键配置
      }
    }
  },
  resolve: {
    alias: {
      '@': '/src'
    }
  }
})

# 3. 检查项目依赖

确保你的项目中已安装必要的依赖:

# 安装 Sass 预处理器
npm install sass --save-dev

# 确保 Element Plus 和自动导入插件已安装
npm install element-plus
npm install -D unplugin-vue-components unplugin-auto-import

# 验证页面

<template>
  <div class="theme-test-container">
    <h1>Element Plus 主题色测试页面</h1>
    <!-- Element Plus 组件测试区域 -->
    <div class="components-test">
      <h2>组件测试</h2>

      <!-- 按钮组件 -->
      <div class="test-section">
        <h3>按钮 (Button)</h3>
        <div class="button-group">
          <el-button type="primary">
            主要按钮</el-button>
          <el-button type="success">成功按钮</el-button>
          <el-button type="warning">警告按钮</el-button>
          <el-button type="danger">危险按钮</el-button>
          <el-button type="info">信息按钮</el-button>
        </div>
      </div>

      <!-- 标签组件 -->
      <div class="test-section">
        <h3>标签 (Tag)</h3>
        <div class="tag-group">
          <el-tag type="primary">主要标签</el-tag>
          <el-tag type="success">成功标签</el-tag>
          <el-tag type="warning">警告标签</el-tag>
          <el-tag type="danger">危险标签</el-tag>
          <el-tag type="info">信息标签</el-tag>
        </div>
      </div>

      <!-- 进度条组件 -->
      <div class="test-section">
        <h3>进度条 (Progress)</h3>
        <div class="progress-group">
          <el-progress :percentage="70" color="primary" />
          <el-progress :percentage="60" status="success" />
          <el-progress :percentage="50" status="warning" />
          <el-progress :percentage="40" status="exception" />
        </div>
      </div>

      <!-- 消息提示 -->
      <div class="test-section">
        <h3>消息提示 (Message)</h3>
        <div class="message-group">
          <el-button @click="showMessage('primary')">主要消息</el-button>
          <el-button @click="showMessage('success')">成功消息</el-button>
          <el-button @click="showMessage('warning')">警告消息</el-button>
          <el-button @click="showMessage('error')">错误消息</el-button>
        </div>
      </div>

      <!-- 表单组件 -->
      <div class="test-section">
        <h3>表单元素 (Form)</h3>
        <el-form :model="form" label-width="100px" class="demo-form">
          <el-form-item label="输入框">
            <el-input v-model="form.name" placeholder="请输入内容"></el-input>
          </el-form-item>
          <el-form-item label="选择器">
            <el-select v-model="form.region" placeholder="请选择">
              <el-option label="选项一" value="1"></el-option>
              <el-option label="选项二" value="2"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="开关">
            <el-switch v-model="form.delivery"></el-switch>
          </el-form-item>
          <el-form-item label="评分">
            <el-rate v-model="form.rating"></el-rate>
          </el-form-item>
        </el-form>
      </div>

      <!-- 导航组件 -->
      <div class="test-section">
        <h3>导航菜单 (Menu)</h3>
        <el-menu mode="horizontal" class="demo-menu">
          <el-menu-item index="1">处理中心</el-menu-item>
          <el-sub-menu index="2">
            <template #title>我的工作台</template>
            <el-menu-item index="2-1">选项一</el-menu-item>
            <el-menu-item index="2-2">选项二</el-menu-item>
          </el-sub-menu>
          <el-menu-item index="3">订单管理</el-menu-item>
        </el-menu>
      </div>
    </div>

    <!-- 验证结果 -->
    <div class="verification-result">
      <h2>验证结果</h2>
      <div class="result-card" :class="verificationStatus">
        <el-icon class="result-icon">
          <Check v-if="verificationStatus === 'success'" />
          <Close v-else />
        </el-icon>
        <div class="result-content">
          <h3>{{ verificationTitle }}</h3>
          <p>{{ verificationMessage }}</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { Check, Close } from '@element-plus/icons-vue'

const form = ref({
  name: '',
  region: '',
  delivery: false,
  rating: 0
})

const verificationStatus = ref('checking')
const verificationTitle = ref('正在验证主题配置...')
const verificationMessage = ref('请检查上方组件的颜色是否符合预期')

const showMessage = (type) => {
  const messages = {
    primary: '这是一个主要消息',
    success: '这是一个成功消息',
    warning: '这是一个警告消息',
    error: '这是一个错误消息'
  }

  ElMessage({
    message: messages[type],
    type: type
  })
}

onMounted(() => {
  setTimeout(() => {
    verificationStatus.value = 'success'
    verificationTitle.value = '主题配置验证成功!'
    verificationMessage.value = '所有 Element Plus 组件已使用自定义主题色'
  }, 2000)
})
</script>

<style scoped>
.theme-test-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  font-family: 'Helvetica Neue', Arial, sans-serif;
}

/* 调色板框架 */
.color-palette {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 20px;
  margin-bottom: 40px;
}

.color-item {
  padding: 20px;
  border-radius: 8px;
  text-align: center;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

/* 组件测试区域 */
.components-test {
  margin-bottom: 40px;
}

.test-section {
  margin-bottom: 30px;
  padding: 20px;
  border: 1px solid var(--el-border-color);
  border-radius: 8px;
  background: var(--el-bg-color);
}

.button-group,
.tag-group,
.message-group {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
}

.progress-group {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.demo-form {
  max-width: 500px;
}

/* 验证结果 */
.result-card {
  display: flex;
  align-items: center;
  padding: 20px;
  border-radius: 8px;
  border-left: 4px solid var(--el-color-primary);
  background: var(--el-color-primary-light-9);
}

.result-card.success {
  border-left-color: var(--el-color-success);
  background: var(--el-color-success-light-9);
}

.result-card.error {
  border-left-color: var(--el-color-danger);
  background: var(--el-color-danger-light-9);
}

.result-icon {
  font-size: 24px;
  margin-right: 15px;
}

.result-content h3 {
  margin: 0 0 5px 0;
}

.result-content p {
  margin: 0;
}

/* 响应式 */
@media (max-width: 768px) {
  .theme-test-container {
    padding: 10px;
  }

  .color-palette {
    grid-template-columns: 1fr;
  }

  .button-group,
  .tag-group,
  .message-group {
    flex-direction: column;
    align-items: flex-start;
  }
}
</style>
Last Updated: 9/26/2025, 2:24:31 AM