TS友好的Element Plus组件二次封装【实用简单】

1,791 阅读1分钟

前言

相信用到过Element Plus 的同学一定会基于自己公司的需求对组件进行二次封装,在这里给大家分享一下我经常使用的封装的一些小技巧,首先封装可能是出于下面三个目的:

  1. 仅仅是为了方便还原设计稿样式,为了更方便覆盖其默认样式
  2. 为了修改某些默认值
  3. 为组件提供新的prop属性用来提供新功能

原则 Concept

不管你是出于哪种目的,我们在对组件二次封装的时候一个重要的原则就是保证组件不被污染!即保证组件原有的输入(props,model,slots...) 和 输出(emit,expose...)都能正常工作。下面以ElInput组件为例展示封装过程

传递组件props

传递$attrs 使用 mergeProps 合并 attrs和props

为了保证组件原有属性能被正常传递,我们可以使用toMerged合并$attrs和重写默认属性或新增props对象,绑定到原有组件:

<el-input v-bind="mergeProps($attrs, props)"></el-input>

使用 withDefaults 设置默认值

type ElInputType = InputInstance
type ZeInputProps = Partial<InputProps> & {/* 可以在此处添加新属性 */}
const props = withDefaults(defineProps<ZeInputProps>(), {
  clearable: true, // 改变el-input clearable 默认值
  /* 可以在此处为新属性添加默认值 */
})

传递插槽 slots

不论是封装什么组件都可以使用v-for v-for="(_, name) in $slots",即使组件插槽相互有逻辑也不会被影响,缺点就是保存的时候vscode vue plugin下提示有点小瑕疵,重复保存几次就好了

  <el-input>
    <template v-for="(_, name) in $slots" #[name]="scope">
      <slot :name="name" v-bind="scope"></slot>
    </template>
  </el-input>

expose 原组件实例方法

1.绑定原有组件 ref

 <el-input ref="rawRef"></el-input>

2.使用 Proxy 进行代理

<script setup lang="ts">
import type { InputInstance } from 'element-plus'
type ElInputType = InputInstance & {}

const rawRef = ref<ElInputType>()

defineExpose<ElInputType>(
  new Proxy(
    {},
    {
      get: (_target, prop) => rawRef.value?.[prop],
      has: (_target, prop) => prop in (rawRef.value || {}),
    },
  ) as ElInputType,
)
</script>

ElInput组件 二次封装

<template>
  <el-input v-bind="mergeProps($attrs, props)" class="ze-input" ref="rawRef">
    <template v-for="(_, name) in $slots" #[name]="scope">
      <slot :name="name" v-bind="scope"></slot>
    </template>
  </el-input>
</template>

<script setup lang="ts">
import type { InputProps } from 'element-plus'
import type { InputInstance } from 'element-plus'
import { mergeProps } from 'vue'
type ElInputType = InputInstance
type ZeInputProps = Partial<InputProps> & {}
const props = withDefaults(defineProps<ZeInputProps>(), {
  clearable: true,
})
const rawRef = ref<ElInputType>()

defineExpose<ElInputType>(
  new Proxy(
    {},
    {
      get: (_target, prop) => rawRef.value?.[prop],
      has: (_target, prop) => prop in (rawRef.value || {}),
    },
  ) as ElInputType,
)
</script>

<style lang="scss" scoped>
.ze-input {
  min-width: 190px; // 添加新样式
  // :deep(xxx) {} 覆盖原有样式
}
</style>

使用示例

image.png Github源码:ZeInput.vue

如果你对element plus其他组件二次封装感兴趣 或者你需要一个全新的,简洁,代码高可用,现代的初始项目不妨看看这个项目:vue-zero-admin