Element Plus 按需导入配置指南

概述

本项目已配置 Element Plus 按需导入,可以自动导入组件和 API,无需手动引入,大幅减少打包体积。

已安装的依赖

{
  "devDependencies": {
    "unplugin-auto-import": "^x.x.x",      // 自动导入 API
    "unplugin-vue-components": "^x.x.x",   // 自动导入组件
    "unplugin-icons": "^x.x.x",            // 自动导入图标
    "@iconify-json/ep": "^x.x.x"           // Element Plus 图标集
  }
}

配置说明

vite.config.ts

import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'

export default defineConfig({
  plugins: [
    vue(),
    
    // 自动导入 Vue 相关函数和 Element Plus API
    AutoImport({
      imports: ['vue', 'vue-router', 'pinia'],
      resolvers: [
        ElementPlusResolver(),
        IconsResolver({
          prefix: 'Icon'
        })
      ],
      dts: 'src/auto-imports.d.ts',
      eslintrc: {
        enabled: true,
        filepath: './.eslintrc-auto-import.json',
        globalsPropValue: true
      }
    }),
    
    // 自动导入组件
    Components({
      resolvers: [
        ElementPlusResolver(),
        IconsResolver({
          enabledCollections: ['ep']
        })
      ],
      dts: 'src/components.d.ts'
    }),
    
    // 图标
    Icons({
      autoInstall: true
    })
  ]
})

使用方法

1. 自动导入 Vue API

无需手动导入 Vue 的 API,直接使用即可:

<script setup lang="ts">
// ❌ 不需要这样导入
// import { ref, computed, onMounted } from 'vue'
// import { useRouter } from 'vue-router'
// import { useStore } from 'pinia'

// ✅ 直接使用
const count = ref(0)
const doubled = computed(() => count.value * 2)
const router = useRouter()

onMounted(() => {
  console.log('组件已挂载')
})
</script>

2. 自动导入 Element Plus 组件

无需手动导入 Element Plus 组件,直接在模板中使用:

<script setup lang="ts">
// ❌ 不需要这样导入
// import { ElButton, ElInput, ElMessage } from 'element-plus'

// ✅ 直接使用 API
const handleClick = () => {
  ElMessage.success('操作成功!')
}
</script>

<template>
  <div>
    <!-- ✅ 直接使用组件 -->
    <el-button type="primary" @click="handleClick">
      点击我
    </el-button>
    
    <el-input v-model="value" placeholder="请输入内容" />
    
    <el-table :data="tableData">
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="age" label="年龄" />
    </el-table>
  </div>
</template>

3. 自动导入图标

使用 Element Plus 图标:

<template>
  <div>
    <!-- 方式一:使用 i-ep 前缀 -->
    <i-ep-edit />
    <i-ep-delete />
    <i-ep-search />
    
    <!-- 方式二:使用 Icon 前缀(配置中设置) -->
    <icon-ep-edit />
    <icon-ep-delete />
    <icon-ep-search />
    
    <!-- 在 Element Plus 组件中使用 -->
    <el-button :icon="Edit">编辑</el-button>
    <el-button>
      <template #icon>
        <i-ep-delete />
      </template>
      删除
    </el-button>
  </div>
</template>

<script setup lang="ts">
// 如果需要在 script 中使用图标组件
import { Edit } from '@element-plus/icons-vue'
</script>

4. 常用组件示例

按钮

<template>
  <el-button>默认按钮</el-button>
  <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 :icon="Search">搜索</el-button>
</template>

表单

<script setup lang="ts">
const formData = ref({
  name: '',
  email: '',
  age: 0
})

const rules = {
  name: [
    { required: true, message: '请输入姓名', trigger: 'blur' }
  ],
  email: [
    { required: true, message: '请输入邮箱', trigger: 'blur' },
    { type: 'email', message: '请输入正确的邮箱', trigger: 'blur' }
  ]
}

const handleSubmit = () => {
  ElMessage.success('提交成功!')
}
</script>

<template>
  <el-form :model="formData" :rules="rules" label-width="80px">
    <el-form-item label="姓名" prop="name">
      <el-input v-model="formData.name" />
    </el-form-item>
    
    <el-form-item label="邮箱" prop="email">
      <el-input v-model="formData.email" type="email" />
    </el-form-item>
    
    <el-form-item label="年龄">
      <el-input-number v-model="formData.age" :min="0" :max="150" />
    </el-form-item>
    
    <el-form-item>
      <el-button type="primary" @click="handleSubmit">提交</el-button>
    </el-form-item>
  </el-form>
</template>

消息提示

<script setup lang="ts">
const showMessage = () => {
  ElMessage.success('操作成功!')
  ElMessage.error('操作失败!')
  ElMessage.warning('警告信息')
  ElMessage.info('提示信息')
}

const showMessageBox = async () => {
  try {
    await ElMessageBox.confirm('确定要删除吗?', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    ElMessage.success('删除成功!')
  } catch {
    ElMessage.info('已取消删除')
  }
}

const showNotification = () => {
  ElNotification({
    title: '成功',
    message: '这是一条成功的提示消息',
    type: 'success'
  })
}
</script>

对话框

<script setup lang="ts">
const dialogVisible = ref(false)

const handleClose = () => {
  dialogVisible.value = false
}
</script>

<template>
  <el-button @click="dialogVisible = true">打开对话框</el-button>
  
  <el-dialog
    v-model="dialogVisible"
    title="提示"
    width="500px"
  >
    <span>这是一段对话框内容</span>
    <template #footer>
      <el-button @click="handleClose">取消</el-button>
      <el-button type="primary" @click="handleClose">确定</el-button>
    </template>
  </el-dialog>
</template>

表格

<script setup lang="ts">
const tableData = ref([
  { id: 1, name: '张三', age: 25, address: '北京' },
  { id: 2, name: '李四', age: 30, address: '上海' },
  { id: 3, name: '王五', age: 28, address: '广州' }
])

const handleEdit = (row: any) => {
  ElMessage.info(`编辑:${row.name}`)
}

const handleDelete = (row: any) => {
  ElMessage.warning(`删除:${row.name}`)
}
</script>

<template>
  <el-table :data="tableData" border stripe>
    <el-table-column prop="id" label="ID" width="80" />
    <el-table-column prop="name" label="姓名" />
    <el-table-column prop="age" label="年龄" />
    <el-table-column prop="address" label="地址" />
    <el-table-column label="操作" width="180">
      <template #default="{ row }">
        <el-button size="small" @click="handleEdit(row)">编辑</el-button>
        <el-button size="small" type="danger" @click="handleDelete(row)">
          删除
        </el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

自动生成的文件

配置完成后,会自动生成以下文件(已添加到 .gitignore):

  • src/auto-imports.d.ts - 自动导入的 API 类型定义
  • src/components.d.ts - 自动导入的组件类型定义
  • .eslintrc-auto-import.json - ESLint 配置(避免 no-undef 错误)

ESLint 配置

如果遇到 ESLint 报错(如 ref is not defined),需要更新 eslint.config.ts

import autoImport from './.eslintrc-auto-import.json'

export default [
  // ... 其他配置
  {
    languageOptions: {
      globals: {
        ...autoImport.globals
      }
    }
  }
]

图标使用指南

Element Plus 图标

<template>
  <!-- 直接使用图标组件 -->
  <i-ep-edit />
  <i-ep-delete />
  <i-ep-search />
  <i-ep-plus />
  <i-ep-close />
  <i-ep-check />
  <i-ep-arrow-left />
  <i-ep-arrow-right />
  <i-ep-upload />
  <i-ep-download />
</template>

图标列表

访问 Element Plus 图标库 查看所有可用图标。

使用方式:

  • 图标名称:Edit → 组件名称:i-ep-editicon-ep-edit
  • 图标名称:Delete → 组件名称:i-ep-deleteicon-ep-delete

优势

✅ 按需导入的好处

  1. 减小打包体积:只打包使用到的组件和 API
  2. 提升开发体验:无需手动导入,代码更简洁
  3. 自动类型提示:自动生成类型定义文件
  4. 避免重复导入:统一管理导入逻辑

📊 打包体积对比

  • 全量导入:~500KB(gzip 后 ~150KB)
  • 按需导入:根据使用情况,通常 ~100-200KB(gzip 后 ~30-60KB)

常见问题

Q1: 组件没有自动导入?

A: 确保:

  1. 组件名称正确(使用 el- 前缀)
  2. 重启开发服务器
  3. 检查 src/components.d.ts 是否生成

Q2: ESLint 报错 “xxx is not defined”?

A: 更新 ESLint 配置,导入 .eslintrc-auto-import.json

Q3: TypeScript 类型提示不工作?

A: 检查 src/auto-imports.d.tssrc/components.d.ts 是否生成,重启 IDE

Q4: 如何使用全局配置?

A: 如果需要全局配置 Element Plus(如国际化、主题),可以在 main.ts 中配置:

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'

const app = createApp(App)

// 全局配置
app.use(ElementPlus, {
  locale: zhCn,
  size: 'default',
  zIndex: 3000
})

但这样会失去按需导入的优势,建议使用 app.config.globalProperties 或 provide/inject。

Q5: 如何自定义主题?

A: 创建 src/styles/element-variables.scss

@forward 'element-plus/theme-chalk/src/common/var.scss' with (
  $colors: (
    'primary': (
      'base': #42b983,
    ),
  ),
);

然后在 main.ts 中导入:

import './styles/element-variables.scss'

参考资源