使用 Vue 3 配合 Element Plus 进行 App 开发是一种很流行的搭配,我也选择了这对组合,此前并不了解前端开发,所以我按照文档进行操作。在全部导入和按需导入里,我选择了感觉会比较精益的按需导入模式。不过,文档在这方面的介绍并不全面。
全部导入
typescript
// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
这是官方文档中提供的全部导入的方法。通过这种方法,我们可以安全的在整个项目的所有地方,使用 Element UI 的组件,不用担心引用和样式的问题。后来我才知道,这可能是一种更好的选择,如果你急功近利想要完成项目,这种方法可能是一种问题比较少的方法。
按需导入
按需导入,分为自动导入和手动导入两种,其中手动导入是比较麻烦的,每用到一个组件,都需要手动 import 这个组件用到的代码和样式,非常麻烦,我直接就跳过了没看。选了利用插件支持的自动导入方法,需要额外的插件支持:
shell
npm install -D unplugin-vue-components unplugin-auto-import
这也是官方比较推荐的方法,Vite 的配置如下:
typescript
// vite.config.ts
import { defineConfig } from 'vite'
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: [
// ...
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
})
不得不说,整个开发体验非常好,到这里,多数情况下引用 Element UI 组件,都很方便,直接写代码就行。不过,仍然有一些,每个人都难免遇到的情况,这个文档没有详细介绍,应该怎么处理。
遇到的问题
我们都知道,一个 Vue 组件 SFC,包含三个部分,<template>
和 <script>
和 <style>
,我发现,在实际使用中,一般来说,引用 Element UI的话,我们都会写在这个 <template>
里面。比如:
typescript
<template>
<el-tree />
</template>
在这种情况下,上文提到的自动导入方案,都会很好地工作。但是,有时候,你会发现,你不止会在 <template>
里面使用到组件。比如,我昨天就撰文说了那个奇怪的问题,就是一种情况。
typescript
<script lang="ts" setup>
const treeRef = ref<InstanceType<typeof ElTree>>(null)
</script>
<template>
<el-tree
ref="treeRef"
/>
</template>
在上面这个代码案例里,我们因为某种原因,需要一个 ElTree 组件的引用,好在代码里操作它,如果你用了 TypeScript 的情况下,如果不声明引用的类型,那么 ElTree 上带有的方法,是不会在 IDE 里提示的,甚至你调用了,还会报错。因为 IDE 提示,不能在 never 类型上使用该方法。虽然说,可能执行的时候是不会有错的,但是你连编译这关可能都过不了。
(所以说,尽量不要选择 TypeScript 除非真的有这个需要,或者跟我一样轴)
但是,这时候我就发现,在 <script>
里出现的 ElTree 的名字,上面提到的自动导入,并不能自动解决。尤其这种在泛型括号里出现的组件名字。解决这种情况方法,昨天的文章我也提及了:
typescript
<script lang="ts" setup>
import type { ElTree } from "element-plus"
</script>
注意上面代码里的 type 这四个字母,如果你去掉,也不会报错,那样就是你直接导入组件而不是导入类型。导入组件,是有副作用的,会导致这个页面的 tree 组件样式缺失。具体原理我这会儿还没懂,大体上就是在自动导入的环境下,你如果手动导入了,会出冲突。
另一个案例
除了这个情况,还有一种情况,你会遇到在 <script>
里出现组件的情况,那就是那些默认没有模版,全动态使用的组件,比如 ElMessageBox 和 ElMessage。
typescript
<script lang="ts" setup>
function callMsg() {
ElMessageBox.confirm(
"一旦执行不可撤销,是否继续?",
"注意",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
}
}
</script>
上面是一个使用的例子,在这个例子里,一开始介绍的按需自动导入,也不会生效。这种情况,还不同于上一种情况,不是出现在类型泛型的尖括号里,而是出现在代码里,这里导入 type 是不行的。我们需要在 vite 的自动导入配置里加入一个 eslint 有关的配置:
typescript
// vite.config.ts
import { defineConfig } from 'vite'
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: [
// ...
AutoImport({
eslintrc: {
enabled: true
},
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
})
注意 13-15 行,这行配置会导致插件自动生成一个文件 .eslintrc-auto-import.json
这个文件,文件名是可以用参数指定自定义的,就不演示了。这个文件在目录下形成后,还要把这个文件告知给 eslint 才能起作用。
javascript
//.eslintrc.cjs
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting',
'./.eslintrc-auto-import.json'
],
parserOptions: {
ecmaVersion: 'latest'
},
ignorePatterns: ['main.js', 'preload.js']
}
注意上面的第 12 行,把新自动生成的文件,加入了配置。除了上述文件,根目录下还有生成一个文件 auto-imports.d.ts
文件,还要将这个文件告知给 ts:
json
//tsconfig.json
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue", "./auto-imports.d.ts"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"types": ["@modyfi/vite-plugin-yaml/modules"]
}
}
注意第 4 行的最后,加入了这个文件,作为一个 include 文件,到此,此种情况就不会再报错了。
结论
这种很重要,而且几乎人人会遇到的情况,官方文档竟然缺失,这让人很遗憾,作为一个小白,我遇到了就是全网到处乱找,而不少文章都是告诉我,遇到了就改成本文第一节提到的方法,改为全量导入。
如果按需导入根本不能解决问题,那么又有什么存在的必要呢?其实我现在还是有点一知半解,为什么我介绍的关于 ElTree 的那种情况,我介绍的这个关于 eslint 和 ts 的配置也解决不了。这些无数人使用的插件都是大漏勺么?随便就漏掉一些很常见的问题的处理。