从实际项目深入理解ElementPlus的几种导入方式

3,538 阅读4分钟

ElementPlus官网中介绍了三种导入方式,分别是完整导入、按需自动导入、(按需)手动导入。但在实际项目中还会有全局导入部分组件以及全局导入和按需导入组合的方式。本文通过github上几个高star数的项目来展示几种导入ElementPlus的方式,并对关键知识加以解释从而加深对这些导入方式的理解。先通过一张图纵览一下几种方式:

1.完整导入

本部分内容参考了element-plus官网和vue3.0-ts-admin项目。

正如官方文档所言,如果你对打包后的文件大小不是很在乎,那么使用完整的导入比较方便。

注意:完整导入后,使用的时候直接用

1.1 导入

main.ts文件

import { createApp } from 'vue'
import ElementPlus from "element-plus";
import "element-plus/lib/theme-chalk/index.css";
import App from './App.vue'

const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')

1.2 使用

如下代码中用到了el-menu,直接使用即可:

<template>
  <div>
    <el-menu
             :collapse="state.isSidebarNavCollapse"
             text-color="#eee"
             active-text-color="#4dbcff"
             :default-active="state.currentMenu"
             class="theme-bg"
             id="menu"
             :unique-opened="true"
             >
      <MENU :menuList="state.sidebarMenu"></MENU>
    </el-menu>
  </div>
</template>

2.按需自动导入

按需自动导入是推荐的导入方式。本节内容参考了vue3-music项目,您可以clone代码进行详细学习。

注意:如果采用自动按需导入的方式,则在使用组件的时候直接使用,不需要任何显示的导入语句。我们看一下按需导入的几个关键环节:

2.1 安装插件

m install -D unplugin-vue-components unplugin-auto-import

2.2 vite配置文件

// 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()],
    }),
  ],
})

unplugin-vue-components/vite是负责组件自动导入的,你可以在不导入和注册组件的情况下在模板中使用想要用到的组件。

unplugin-vue-components内置了流行UI组件库的resolvers(例如element-plus的),我们可以看一下unplugin-vue-components中element-plus的resolver部分源码:

// https://github.com/antfu/unplugin-vue-components/blob/main/src/core/resolvers/element-plus.ts
// resolveComponent方法中有一段代码:
return {
  from: `element-plus/lib/el-${partialName}`,
  sideEffects: getSideEffectsLegacy(partialName, options),
}
// getSideEffectsLegacy:
function getSideEffects(dirName: string, options: ElementPlusResolverOptionsResolved): SideEffectsInfo | undefined {
  const { importStyle, ssr } = options
  const themeFolder = 'element-plus/theme-chalk'
  const esComponentsFolder = 'element-plus/es/components'

  if (importStyle === 'sass')
    return ssr ? `${themeFolder}/src/${dirName}.scss` : `${esComponentsFolder}/${dirName}/style/index`
  else if (importStyle === true || importStyle === 'css')
    return ssr ? `${themeFolder}/el-${dirName}.css` : `${esComponentsFolder}/${dirName}/style/css`
}

看到这些代码也大概知道其作用了:引入组件和样式。

unplugin-auto-import/vite是用于自动导入API的。例如下面这段代码,可以在不引入ref的情况下使用ref

const count = ref(0)
const doubled = computed(() => count.value * 2)

2.3 使用

下面代码中使用了ElScrollbar,既没有引入组件也没有引入样式:

<template>
  <div class="w-screen h-screen flex items-stretch overflow-hidden">
    <div class="flex-1 flex flex-col ">
      <div class="flex-1 overflow-hidden">
        <ElScrollbar>
          <div class="container mx-auto">
            <RouterView/>
          </div>
        </ElScrollbar>
      </div>
    </div>  
    <PlayList/>  
  </div>
</template>
<script setup lang="ts">
  import PlayList from "@/components/layout/playList/PlayList.vue";</script>
<style lang="scss">
</style>

3.按需手动导入

本节内容参考了element-plus官网。

3.1安装插件

安装插件的原因是要通过插件来导入样式。

npm i unplugin-element-plus -D

3.2 vite配置文件

import { defineConfig } from 'vite'
import ElementPlus from 'unplugin-element-plus/vite'

export default defineConfig({
  // ...
  plugins: [ElementPlus()],
})

unplugin-element-plus插件的原理是做自动转换,检查引用组件的import语句,自动增加引用组件样式的import语句:

import { ElButton } from 'element-plus'

//    ↓ ↓ ↓ ↓ ↓ ↓

import { ElButton } from 'element-plus'
import 'element-plus/es/components/button/style/css'

3.3 使用

<template>
  <el-button>I am ElButton</el-button>
</template>
<script>
  import { ElButton } from 'element-plus'
  export default {
    components: { ElButton },
  }
</script>

4.全局导入和按需导入组合使用

本部分示例参考了vue-element-plus-admin项目,您可以clone整个项目进行学习。

4.1 全局导入

plugins/elementPlus/index.ts

import type { AppContext, Plugin } from 'vue'

// 需要全局引入一些组件,如ElScrollbar,不然一些下拉项样式有问题
import { ElLoading, ElScrollbar } from 'element-plus'

const plugins = [ElLoading] as Plugin[]

const components = [ElScrollbar]

export const setupElementPlus = (app: AppContext['app']) => {
  plugins.forEach((plugin) => {
    app.use(plugin)
  })
  
  components.forEach((component) => {
    app.component(component.name, component)
  })
}

此文件中对ElLoading和ElScrollbar进行了全局的引入,其中ElLoading作为插件进行安装,ElScrollbar作为全局组件安装。

这里简要说明为什么ElLoading可以作为插件引入。vue应用(app)实例的use方法用于安装vue.js的插件。如果插件是一个对象,则它必须暴露一个 install 方法。如果插件本身是一个函数,则它将被视为 install 方法。我们看一下element-plus中ElLoading的源码:

//packages/components/loading/index.ts
export const ElLoading = {
  install(app: App) {
    app.directive('loading', vLoading)
    app.config.globalProperties.$loading = Loading
  },
  directive: vLoading,
  service: Loading,
}

可以看到ElLoading导出了一个对象,并且此对象拥有install方法,所以ElLoading可以作为vue的插件使用。

在main.ts中导入setupElementPlus方法传入app实例即可:

// 引入element-plus
import { setupElementPlus } from '@/plugins/elementPlus'
import App from './App.vue'
const app = createApp(App)
setupElementPlus(app)

4.2 手动按需导入

在手动按需导入的时候我们需要单独引入要使用的组件,但是对于组件的样式文件如何处理呢?对于样式可以使用插件进行自动转换。

import styleImport, { ElementPlusResolve } from 'vite-plugin-style-import'

export default ({ command, mode }: ConfigEnv): UserConfig => {
  return {
    base: env.VITE_BASE_PATH,
    plugins: [
      Vue(),
      VueJsx(),
      WindiCSS(),
      styleImport({
        resolves: [ElementPlusResolve()],
        libs: [{
          libraryName: 'element-plus',
          esModule: true,
          resolveStyle: (name) => {
            return `element-plus/es/components/${name.substring(3)}/style/css`
          }
        }]
      }),
    ]
}

这里我们使用到了vite-plugin-style-import (注意项目中使用的是1.4.1版本,现在已经是2.0.0版本了),该插件可按需导入组件库样式,注意只是样式!由于我们的场景是开发着已按需导入了组件,因此仅样式不是按需导入的,因此只需按需导入样式即可。插件的原理也是进行转换,例如:

import { ElButton } from 'element-plus';

        ↓ ↓ ↓ ↓ ↓ ↓

// dev
import { Button } from 'element-plus';
import 'element-plus/lib/theme-chalk/el-button.css`;

// prod
import Button from 'element-plus/lib/el-button';
import 'element-plus/lib/theme-chalk/el-button.css';

5.按需全局引入

本节内容参考了vue3-admin项目,您可以clone下来详细学习。

5.1 按需全局引入要使用的组件

main.js文件中引入了项目要使用的组件:

import { 
  ElButton,
  ElContainer,
  ElAside,
  //巴拉巴拉一大堆
  ElFormItem,
  ElInput,
  ElPopover,
  ElTag,} from 'element-plus'
app.use(ElButton)
    .use(ElContainer)
    // 巴拉巴拉一大堆
    .use(ElMain)
    .use(ElFooter)
    .use(ElMenu)

那么问题来了,这些组件的样式文件怎么引入?一个一个的引入也未尝不可,但是好费劲啊~那就自动引入!

5.2 vite配置文件

import vitePluginImport from 'vite-plugin-babel-import';
export default ({ mode }) =>  defineConfig({
  plugins: [
    vue(),
    vitePluginImport([
      {
        libraryName: 'element-plus',
        libraryDirectory: 'es',
        style(name) {
          return `element-plus/lib/theme-chalk/${name}.css`;
        },
      }
    ])
  ],
})

这里使用到了vite-plugin-babel-import,它也是一个自动导入的插件,会对导入内容进行转换,例如:

import { Button } from 'vant';

        ↓ ↓ ↓ ↓ ↓ ↓

import Button from 'vant/es/button';
import 'vant/es/Button/index.css';

6.总结

本文结合实际项目分析了ElementPlus的导入方式,可以看出:

(1)完整导入对于开发者来说是最省事的,不需要对vite配置文件进行配置,但是会导致那些没有用到的组件也会被导入进来,导致整体打包体积大。

(2)而按需自动导入需要安装插件,然后对vite配置文件进行配置,虽然配置需要花点时间理解一下,但是在使用组件的时候就非常方便了,不需要进行导入。并且也不会导入没有用到的组件。

(3)按需手动导入也是为了避免导入过多用不到的内容。我们希望在导入的时候只导入组件而组件的样式交给插件来自动导入。所以按需手动导入也需要安装相应的插件和对vite配置文件进行配置。

除了介绍官网介绍的导入方式之外,我们又介绍了全局导入和按需导入组合使用的方式以及全局的按需导入方式。在介绍自动导入样式的时候我们介绍了一些插件的使用和作用。感觉ElementPlus导入方式也好还是编程也罢就像打拳一样是有套路的又不是死的,所以在实际项目中要灵活运用。