添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
npm install element-plus --save

建议使用 按需导入 ,官方推荐使用 unplugin-vue-components unplugin-auto-import 这两款插件实现自动导入,来弥补按需导入的一些缺点(手动注册组件等)。

# 安装插件
npm install -D unplugin-vue-components unplugin-auto-import

配置 Vite:

// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    // ElementPlus 自动导入
    AutoImport({
      resolvers: [ElementPlusResolver()]
    }),
    Components({
      resolvers: [ElementPlusResolver()]
<el-button type="primary">Primary</el-button>

Element Plus 组件默认使用英语,例如日期组件:

要想使用其他语言(如中文)需要全局配置国际化。

完整导入方式可以在注册的时候通过 locale 选项配置。

按需导入需要使用官方提供的 Vue 组件进行配置:

<!-- src\App.vue -->
<template>
  <el-config-provider :locale="locale">
    <router-view />
  </el-config-provider>
</template>
<script setup lang="ts">
import locale from 'element-plus/lib/locale/lang/zh-cn'
</script>

效果(需要刷新页面使配置生效):

如果想要像官方案例一样在项目中直接使用 Element Plus 的图标,需要全局注册组件,官方自动导入的插件还在开发中,当前手动全局注册:

// src\plugins\element-plus.ts
import { App } from 'vue'
import * as ElIconModules from '@element-plus/icons-vue'
export default {
  install(app: App) {
    // 批量注册 Element Plus 图标组件
    // 或者自定义 ElIconModules 列表
    for (const iconName in ElIconModules) {
      app.component(iconName, (ElIconModules as any)[iconName])
// src\main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import elementPlus from './plugins/element-plus'
// 加载全局样式
import './styles/index.scss'
createApp(App)
  .use(router)
  .use(store)
  .use(elementPlus)
  .mount('#app')

API 和 组件自动导入

Element Plus 实现自动导入安装用的插件不仅仅用于它自己,实际上这两个插件是可以应用到各种框架和库中。

unplugin-vue-components

unplugin-vue-components 插件用于自动识别 Vue 模板中使用的组件,自动按需导入和注册。

它提供了多个可配置的 UI 库的解析器,查看 《Importing from UI Libraries》 部分。

在 TypeScript 项目中会生成 components.d.ts 文件,自动补充更新组件的类型声明文件。

**注意:**插件自动识别的是 template 模板中使用的组件,可以查看 components.d.ts 确认是否已被识别。

unplugin-auto-import

unplugin-auto-import 插件可以在 Vite、Webpack、Rollup 和 esbuild 环境下自动按需导入配置库的常用 API,如 Vue 的 ref,不需要手动 import

可以通过 imports 配置项配置自动导入的 API(预设或自定义规则),也可以通过 resolvers 配置组件库的解析器(如 Element Plus)。

支持 TypeScript 的项目中,插件安装后会在项目根目录生成 auto-imports.d.ts 文件,当配置自动导入时,会自动补充配置库的 API 对应的类型声明。

注意:auto-imports.d.ts 文件默认会被 ESLint 校验,报错 <变量> is defined but never used.,可以忽略 ESLint 对该文件的校验。

配置API 自动导入

配置 Vue 、Vue Router 和 Pinia 的 API 自动导入:

// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    AutoImport({
      imports: [
        // presets
        'vue',
        'vue-router',
        'pinia'
      eslintrc: {
        enabled: true,
        filepath: './.eslintrc-auto-import.json',
        globalsPropValue: true
      // ElementPlus 自动导入
      resolvers: [ElementPlusResolver()]
    }),

保存生效后,auto-imports.d.ts 会自动填充内容,并且会在项目根目录生成 .eslintrc-auto-import.json eslint 全局变量配置。

需要手动的将这两个文件添加到 TypeScript 和 ESLint 配置文件中:

// tsconfig.json
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "auto-imports.d.ts"],
  "references": [{ "path": "./tsconfig.node.json" }]
// .eslintrc.js
module.exports = {
  extends: [
    // unplugin-auto-import
    './.eslintrc-auto-import.json'

忽略 auto-imports.d.ts ESLint 校验。

# .eslintignore
auto-imports.d.ts

建议重启编辑器使配置生效。

现在就可以直接使用 Vue、Vue Router 和 Pinia 的 API,而不需要手动 import 了。

例如,可以注释下面几个 API 的导入:

<!-- src\layout\AppHeader\Breadcrumb.vue -->
<script setup lang="ts">
// import { useRouter } from 'vue-router'
// import { computed } from 'vue'
const router = useRouter()
const routes = computed(() => {
  return router.currentRoute.value.matched.filter(item => item.meta.title)
</script>
// src\store\index.ts
// import { defineStore } from 'pinia'
const useStore = defineStore('main', {
export default useStore
// src\main.ts
// import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// import { createPinia } from 'pinia'
import elementPlus from './plugins/element-plus'
 
  1. 不是全部 API,例如 Vue Router 的 createRouter 就不会导入。具体可以自动导入的 API 参考 unplugin-auto-import/src/presets
  2. 生成 .eslintrc-auto-import.json 文件后如不需要增加配置建议将 enabled: true 设置为 false,否则每次都会生成这个文件。

单独引用 ElementPlus 组件

自动按需引入的原理是通过识别 <template> 中使用的组件自动导入,这就导致如果使用的是 ElMessage 这类直接在 JS 中调用方法的组件,插件并不会识别并完成自动导入。

  • 在 Vue 单文件组件的 <script> 中使用
  • 在 Axios 拦截器中使用

所以这类组件需要进行手动操作:

  • 手动 import 导入组件(完整引入也需要手动 import
  • 手动导入样式文件(element-plus/theme-chalk/xxx.css

例如常用的 ElMessage 组件:

import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/el-message.css'
ElMessage.success('成功使用')

不过这样还有个问题,因为有的组件中还使用了其他 Element 组件,如 ElMessageBox 中的确认按钮使用了 ElButton 组件,虽然渲染成功,但由于不是通过插件自动导入的,所以没有任何样式。

如果是在 Vue 单文件组件中使用的,并且模板中使用了 <el-button>,则会触发自动导入组件的样式文件。

所以建议按需引入的方式,仍然引入完整的样式文件,避免这类边界问题。

// src\plugins\element-plus.ts
import { App } from 'vue'
import * as ElIconModules from '@element-plus/icons-vue'
import 'element-plus/theme-chalk/index.css'
export default {
  install(app: App) {
    // 批量注册 Element Plus 图标组件
    // 或者自定义 ElIconModules 列表
    for (const iconName in ElIconModules) {
      app.component(iconName, (ElIconModules as any)[iconName])
import { ElMessage } from 'element-plus'
// 不再需要单独引入组件样式
// import 'element-plus/theme-chalk/el-message.css'
ElMessage.success('成功使用')

Vue 全局属性(globalProperties)

官方文档:

Vue 2 中使用 Vue.prototype 可以一次性设置所有 Vue 实例全局(this)访问的变量和方法。

Vue 3 改为通过根实例上的 app.config.globalProperties 对象注册该实例(app)内所有组件实例访问的全局属性,以代替 Vue 2 修改全部根实例的方式。

全局注册 ElementPlus 消息提示组件

如果完整引入了 Element Plus,就会自动为 app.config.globalProperties 添加一些组件的全局方法(如 ElMessage$messageElMessageBox$msgbox$alert 等)。

但如果使用的按需引入的方式,使用这类组件时,则需要在使用的模块中手动导入组件及组件样式。

为了减少在 Vue 组件中重复的导入,可以将它们注册为 Vue 实例的全局变量(变量名参考完整引入注册的名称):

// src\plugins\element-plus.ts
import { App } from 'vue'
import * as ElIconModules from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import 'element-plus/theme-chalk/index.css'
export default {
  install(app: App) {
    // 批量注册 Element Plus 图标组件
    // 或者自定义 ElIconModules 列表
    for (const iconName in ElIconModules) {
      app.component(iconName, (ElIconModules as any)[iconName])
    // 将消息提示组件注册为全局方法
    app.config.globalProperties.$message = ElMessage
    app.config.globalProperties.$msgBox = ElMessageBox

使用全局变量

可以在选项式 API 中通过 this.<globalProperty>访问全局变量,或者在模板中直接使用:

<template>
  <button @click="$message.success('可以在模板中直接使用')">
  </button>
</template>
<script lang="ts">
export default defineComponent({
  mounted() {
    this.$message.success('Options API 成功使用')
</script>

在 setup 中使用全局变量

官方并没有介绍如何在 setup()<script setup> 中使用全局变量的方式。

因为 app.config.globalProperties 的目的就是为了替代 2.x 的 Vue.prototype 使用,随着全局 API 的更新,不会再有一次性的 Vue 全局配置,而应为每个根实例进行单独配置。

这本就不是为了应用在 setup 中的,你应该直接导入内容或者在 setup 中使用 provide/inject

参考 Issues:

provide/inject 方式

<!-- 父级组件,如 App.vue -->
<script setup>
import { ElMessage } from 'element-plus'
provide('$message', ElMessage)
</script>
<!-- 子孙组件 -->
<script setup>
const $message = inject('$message')
onMounted(() => {
  $message.success('setup - provide/inject 成功使用')
</script>

setup 中获取实例方式(不推荐)

还有一种的方式,Vue 对外暴露了一个 API getCurrentInstance() 可以访问内部组件实例,通过它可以访问到根实例的全局变量:

<script setup lang="ts">
const instance = getCurrentInstance()
onMounted(() => {
  instance.proxy.$message.success('setup - getCurrentInstance() 成功使用')
  // 也可以使用 appContext
  console.log(instance.appContext.config.globalProperties.$message === instance.proxy.$message) // true
</script>
<script lang="ts">
export default defineComponent({
  mounted() {
    console.log(this.instance.proxy === this) // true
</script>

使用的方式有很多,建议使用安全的方式,如直接导入或在选项 API 下使用。

全局变量 TypeScript 类型声明

添加类型声明文件:

// src\types\global.d.ts
import { ElMessage, ElMessageBox } from 'element-plus'
declare module 'vue' {
  // vue 全局属性
  export interface ComponentCustomProperties {
    $message: typeof ElMessage
    $msgBox: typeof ElMessageBox

基于 Axios 封装请求模块

npm i axios
// src\utils\request.ts
import axios from 'axios'
import { ElMessage } from 'element-plus'
// 在 plugins/element-plus.ts 引入了全部组件样式,这里不需额外引入
// 创建 axios 实例
const request = axios.create({
  baseURL: 'http://localhost:5000/api/admin'
// 请求拦截器
request.interceptors.request.use(function (config) {
  // 统一设置用户身份 token
  return config
}, function (error) {
  return Promise.reject(error)
// 响应拦截器
request.interceptors.response.use(function (response) {
  // 统一处理接口响应错误,如 token 过期无效、服务端异常等
  if (response.data.status && response.data.status !== 200) {
    ElMessage.error(response.data.msg || '请求失败,请稍后重试')
    return Promise.reject(response.data)
  return response
}, function (error) {
  return Promise.reject(error)
export default request

接口请求全部放在 src/api 目录下组织:

// src\api\common.ts
// 公共基础接口封装
import request from '@/utils/request'
export const demo = () => {
  return request({
    method: 'GET',
    url: '/demo'
<!-- src\views\login\index.vue -->
<template>
  </div>
</template>
<script setup lang="ts">
import { demo } from '@/api/common'
import { onMounted } from 'vue'
onMounted(() => {
  demo().then(res => {
    console.log(res.data)
    // {"msg":"ok","status":200,"data":{"title":"Hello World","date":1649412637487}}
</script>

封装响应数据的接口类型

当前获取的 res 是 Axios 包装的响应对象,后端返回的真实数据没有声明类型,所以 IDE 无法提供智能提示,所以要手动声明响应数据的类型。

request 不支持响应数据泛型,所以要改用支持泛型的 request.<method> 发送请求。

export const demo = () => {
  return request.get<{
    status: number
    msg: string
    data: {
      title: string
      date: number
  }>('/demo')

现在 IDE 就可以自动提示 res.data 下的字段了。

但是每个接口都会返回 statusmsgdata 字段,为了避免重复声明,可以将它们封装成一个接口类型(interface),将 data 定义为一个泛型:

interface ResponseData<T = any> {
  status: number
  msg: string
  data: T
export const demo = () => {
  return request.get<ResponseData<{
    title: string
    date: number
  }>>('/demo')

封装泛型请求方法

现在访问响应数据的 data 字段需要通过 res.data.data.title

如果想要简洁一些,如 res.title,可以在请求后返回 .then(res => res.data.data)

这样就必须在每个请求后添加这个操作。

通常我们在 axios 拦截器中进行处理,但是 request.get() 返回类型仍会是 Axios 封装的对象(AxiosResponse)。

虽然运行正常,但智能提示会失效。

可以封装一个接收泛型的方法,内部调用 request()

// src\utils\request.ts
import axios, { AxiosRequestConfig } from 'axios'
export default <T = any>(config: AxiosRequestConfig) => {
  return request(config).then(res => (res.data.data || res.data) as T)

不过这样就不能使用 request.get() 方式发送请求了:

// 之前定义的 interface ResponseData 就不需要了
interface DemoData {
  title: string
  date: number
export const demo = () => {
  return request<DemoData>({
    method: 'GET',
    url: '/demo'

这个方式无法使用 request.<method> 方式发送请求,有利有弊,根据个人习惯选择使用。

提取接口类型模块

一般接口的响应数据的格式可能会在多个地方用到,为了可以复用它们的接口类型,可以将其单独提取到一个模块。

src/api 目录下创建 types 文件夹用于存放 API 相关的类型模块:

// src\api\types\common.ts
export interface DemoData {
  title: string
  date: number
// src\api\common.ts
// 公共基础接口封装
import request from '@/utils/request'
import { DemoData } from '@/api/types/common'
export const demo = () => {
  return request<DemoData>({
    method: 'GET',
    url: '/demo'
<!-- src\views\login\index.vue -->
<template>
  </div>
</template>
<script setup lang="ts">
import { demo } from '@/api/common'
import { DemoData } from '@/api/types/common'
import { onMounted, ref } from 'vue'
const data = ref<DemoData>()
onMounted(() => {
  demo().then(res => {
    data.value = res
    console.log(data.value.title)
</script>

环境变量和模式

环境变量和模式 | Vite 官方中文文档

一般会给项目的接口配置不同环境的基础地址(baseUrl),这通常会配置到环境变量中。

Vite 在一个特殊的 import.meta.env.[variable] 对象上暴露环境变量,构建时这些环境变量会作为字符串识别被静态替换,所以不能使用动态的 key 取值,如 import.meta.env[variable]

Vite 支持和 Vue CLI 一样的方式,通过 .env.[mode] 文件指定环境变量。

与 Vue CLI 不同的是,后者的自定义变量必须以 VUE_APP_ 开头,而 Vite 则必须以 VITE_ 开头。

配置环境变量

值会作为字符串替换,可以不加引号,除非包含 #

# .env.development
# 开发模式下加载的环境变量
VITE_API_BASEURL=http://localhost:5000/api/admin
# .env.production
# 生产模式下加载的环境变量
VITE_API_BASEURL=http://localhost:5000/api/admin
// src\utils\request.ts
import axios, { AxiosRequestConfig } from 'axios'
// 创建 axios 实例
const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASEURL

注意:修改环境变量需要重启 Vite(npm run dev)才会生效。

环境变量 TypeScript 支持

Vite 只提供了默认的环境变量(MODEBASE_URLPRODDEV)的 TS 类型定义,用户自定义的环境变量需要手动添加类型定义。

// src\env.d.ts
// Vite 环境变量
// eslint-disable-next-line no-unused-vars
interface ImportMetaEnv {
  readonly VITE_API_BASEURL: string
 

由于定义了 interface 而没有使用,eslint 会报错,可以对这行代码禁用这个规则。

通常情况下,前端项目和后端项目都是分开部署的,而服务端接口都有跨域限制,解决跨域的方式很多,前端最主流的解决方案就是两种:

开发环境生产环境
在服务端配置 CORS在服务端配置 CORS
配置开发服务器代理,如 vite 的 server.proxy 和 Vue CLI 的 devServer.proxy配置生产服务器代理,如 nginx

一般后端开发懒得配 CORS,前端常用的解决方案就是配置服务器反向代理(proxy)。

原理就是搭建一个中转服务器来转发请求规避跨域的问题,接口请求本地地址,由运行前端代码的服务器转发到目标服务器。

修改请求基础路径为本地路径(约定 /api 开头的请求路径都是需要转发的接口请求):

# .env.development
# 开发模式下加载的环境变量
VITE_API_BASEURL=/api
 

记得重启使环境变量生效。

配置 /api 的反向代理:

// vite.config.ts
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        // 目标地址
        target: 'http://localhost:5000/api/admin',
        // 有的服务器会验证 origin
        // 默认接收到的是真实的 origin 即 http://localhost:3000
        // 设置 changeOrigin 为 true 后,代理服务器就会把 origin 修改为 target 的 origin(http://localhost:5000)
        // 一般建议加上此设置
        changeOrigin: true,
        // 路径重写
        // 路径即请求路径,如 /api/demo
        // 默认会这样拼接: <target.path><path> 如 http://localhost:5000/api/admin/api/demo
        // 重新后为 http://localhost:5000/api/admin/demo
        rewrite: path => path.replace(/^\/api/, '')
 

PS:当前案例使用的服务端代码默认配置了 CORS,可以删掉 app.use(cors()) 测试跨域效果。

配置 Vue RouterVite 创建的项目没有集成 Vue Router,需要手动安装集成。Vue 3 使用最新版本的 Vue Router v4.x。# 安装npm install vue-router@4创建路由配置文件:&lt;!-- src\views\home\index.vue --&gt;&lt;template&gt; &lt;div&gt; 首页 &lt;/div&gt;&lt;/template&gt;&lt;script setup lang= Vite + Vue3 + Ts + router + Vuex + axios + eslint 、prettier、stylelint、husky、gitCommit 1:模版为博客中所描述所有代码,运行即用,需要注意,一定要下载博文中的依赖才可以启动 2:项目集成多种插件,打造企业级开发模版、拆箱即用 3:安装 pnpm i 4:部署打包 npm build 5:运行 npm run dev (1) 创建组件的写法 写法: Vue.component("组件名",{ //xx }); //这里是全局注册组件的写法 Vue.component()函数的第一个参数就是组件名, 比如Vue.component(“my-comname”,{ //xx}}); 那么my-comname就是新建组件的名称; (2)注意: 为了能在模板中使用,这些组件必须先注册以便 ...
这个提示非常明显,就是你定义的这个XXX is defined butnever used.(no-unused-vars)被定义但从未使用,没有使用no-unused-vars 解决方法: 1、在项目中找到‘.eslintrc.js’ 文件,在rules里面添加上'no-unused-vars': 'off' 就不会报错了 如图所示:
环境:vue3+typescript+element-plus 全局引入element之后,element已经在 app.config.globalProperties 添加了全局方法 $message 所以在options API中可以直接使用 mounted(){ (this as any).$message.success("this.$message"); 在Composition API中setup方法传入了两个变量,props和context,context作为上下文...
vite+vue3项目中配置封装axios过程中,用到了elloading与elmessage,测试的时候发现不显示。 import Axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'; import { ElLoading, ElMessage } from 'element-plus'; let loadingInstance: any; const startLoad
使用Vue3+Vite+TS基于Element plus 二次封装业务组件,注册挂载为全局使用,代码简洁了许多。封装好我们的业务组件今后开发中遇到时,就可以直接使用啦!前提,你已经安装好了相关node环境依赖,查看vite的start连接一般的 最后,就可以看到这样 二、安装Element plus 依赖 首先要这样,我们进入element plus的官方文档 执行如下安装命令 我们再这样在项目中引入,直接全局引入,打包后体积不会相差多少,而且全局引入代码整洁好看。
vue3是一个流行的前端框架,vite是一个快速的构建工具,而axios是一个常用的HTTP客户端库。在使用这些工具的时候,我们有时会遇到跨域问题,需要使用代理来解决。但是使用代理后,如果接口出现了错误,vue的开发者工具或者浏览器控制台可能不会显示出来,这可能会给我们的开发和调试带来很大的不便。 这个问题的出现可能是由于代理不会把错误的信息从服务器传递回来,或者浏览器没有显示代理返回的错误信息。一种解决方法是在axios的拦截器中添加一个error拦截器。这个拦截器会在接口出错时被触发,我们可以在拦截器里面进行错误处理,并将错误信息打印出来。例如: ```js // 在创建 axios 实例时设置拦截器 const axiosInstance = axios.create({ baseURL: '/', timeout: 1000, headers: {'X-Custom-Header': 'foobar'} axiosInstance.interceptors.response.use( response => { // 正常返回 response return response; error => { // 出现错误时触发 console.error(error); // 返回错误信息 return Promise.reject(error); 这样,在使用axios发送请求的时候,如果接口出错了,就会在控制台中打印出错误信息,方便我们进行调试和处理。