对element-plus的组件二次修改-自定义组件

背景

本文是将element-plus的组件提取出来作为业务使用的自定义组件,以transfer组件为例子。

对于element-ui的改造,可以看这篇

正常我们使用transfer效果如下:

当我想给每一个option后面添加一些文字,这就属于自定义组件的范畴了,如下图所示

我给transfer传入的数据里没有哇啦啦啦,我是在组件代码里添加的。

实现过程

我使用了element-plus@2.4.2。在一个正常的引入了element-plus组件的项目中,我们使用方式如下,在HelloWorld.vue中使用transfer。

ts 复制代码
<template>
  <div class="greetings">
    <el-transfer v-model="value" :data="data" style="display: block;" />
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue'

interface Option {
  key: number
  label: string
  disabled: boolean
}

const generateData = () => {
  const data: Option[] = []
  for (let i = 1; i <= 15; i++) {
    data.push({
      key: i,
      label: `Option ${i}`,
      disabled: i % 4 === 0,
    })
  }
  return data
}

const data = ref<Option[]>(generateData())
const value = ref([])
</script>

接下来我们将/node_modules/element-plus/es/components/transfer这个文件夹复制到HelloWorld.vue同级目录下,如下图:

然后在HelloWorld.vue中引入,如下:

ts 复制代码
<template>
  <div class="greetings">
    <customTransfer v-model="value" :data="data" style="display: block;" />
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import customTransfer from './transfer/index.mjs'

interface Option {
  key: number
  label: string
  disabled: boolean
}

const generateData = () => {
  const data: Option[] = []
  for (let i = 1; i <= 15; i++) {
    data.push({
      key: i,
      label: `Option ${i}`,
      disabled: i % 4 === 0,
    })
  }
  return data
}

const data = ref<Option[]>(generateData())
const value = ref([])
</script>

运行项目,会报很多的错误,接下来我不会一个一个讲,直接贴代码修改处

  1. transfer/src/transfer.mjs

原来:

ts 复制代码
import { isNil } from 'lodash-unified';
import '../../../utils/index.mjs';
import '../../../constants/index.mjs';
import { buildProps, definePropType } from '../../../utils/vue/props/runtime.mjs';
import { mutable } from '../../../utils/typescript.mjs';
import { isArray } from '@vue/shared';
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '../../../constants/event.mjs';

改为:

ts 复制代码
import { isNil } from 'lodash-unified';
import 'element-plus/es/utils/index.mjs';
import 'element-plus/es/constants/index.mjs';
import { buildProps, definePropType } from 'element-plus/es/utils/vue/props/runtime.mjs';
import { mutable } from 'element-plus/es/utils/typescript.mjs';
import { isArray } from '@vue/shared';
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from 'element-plus/es/constants/event.mjs';
  1. transfer/index.mjs

原先为:

ts 复制代码
import '../../utils/index.mjs';
import Transfer from './src/transfer2.mjs';
export { LEFT_CHECK_CHANGE_EVENT, RIGHT_CHECK_CHANGE_EVENT, transferCheckedChangeFn, transferEmits, transferProps } from './src/transfer.mjs';
import { withInstall } from '../../utils/vue/install.mjs';

改为:

ts 复制代码
import 'element-plus/es/utils/index.mjs';
import Transfer from './src/transfer2.mjs';
export { LEFT_CHECK_CHANGE_EVENT, RIGHT_CHECK_CHANGE_EVENT, transferCheckedChangeFn, transferEmits, transferProps } from './src/transfer.mjs';
import { withInstall } from 'element-plus/es/utils/vue/install.mjs';
  1. transfer/src/transfer2.mjs

原先为:

ts 复制代码
import { defineComponent, useSlots, reactive, ref, computed, watch, h, openBlock, createElementBlock, normalizeClass, unref, createVNode, withCtx, renderSlot, createElementVNode, toDisplayString, createCommentVNode } from 'vue';
import '../../../utils/index.mjs';
import '../../../hooks/index.mjs';
import { ElButton } from '../../button/index.mjs';
import { ElIcon } from '../../icon/index.mjs';
import '../../form/index.mjs';
import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
import { transferProps, transferEmits } from './transfer.mjs';
import './composables/index.mjs';
import TransferPanel from './transfer-panel2.mjs';
import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
import { useLocale } from '../../../hooks/use-locale/index.mjs';
import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
import { useFormItem } from '../../form/src/hooks/use-form-item.mjs';
import { usePropsAlias } from './composables/use-props-alias.mjs';
import { useComputedData } from './composables/use-computed-data.mjs';
import { useCheckedChange } from './composables/use-checked-change.mjs';
import { useMove } from './composables/use-move.mjs';
import { debugWarn } from '../../../utils/error.mjs';
import { isEmpty, isUndefined } from '../../../utils/types.mjs';

改为:

ts 复制代码
import { defineComponent, useSlots, reactive, ref, computed, watch, h, openBlock, createElementBlock, normalizeClass, unref, createVNode, withCtx, renderSlot, createElementVNode, toDisplayString, createCommentVNode } from 'vue';
import 'element-plus/es/utils/index.mjs';
import 'element-plus/es/hooks/index.mjs';
import { ElButton } from 'element-plus/es/components/button/index.mjs';
import { ElIcon } from 'element-plus/es/components/icon/index.mjs';
import 'element-plus/es/components/form/index.mjs';
import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
import { transferProps, transferEmits } from './transfer.mjs';
import './composables/index.mjs';
import TransferPanel from './transfer-panel2.mjs';
import _export_sfc from 'element-plus/es/_virtual/plugin-vue_export-helper.mjs';
import { useLocale } from 'element-plus/es/hooks/use-locale/index.mjs';
import { useNamespace } from 'element-plus/es/hooks/use-namespace/index.mjs';
import { useFormItem } from 'element-plus/es/components/form/src/hooks/use-form-item.mjs';
import { usePropsAlias } from './composables/use-props-alias.mjs';
import { useComputedData } from './composables/use-computed-data.mjs';
import { useCheckedChange } from './composables/use-checked-change.mjs';
import { useMove } from './composables/use-move.mjs';
import { debugWarn } from 'element-plus/es/utils/error.mjs';
import { isEmpty, isUndefined } from 'element-plus/es/utils/types.mjs';
  1. transfer/src/composables/use-move.mjs

原先为:

ts 复制代码
import '../../../../constants/index.mjs';
import { usePropsAlias } from './use-props-alias.mjs';
import { UPDATE_MODEL_EVENT, CHANGE_EVENT } from '../../../../constants/event.mjs';

改为:

ts 复制代码
import 'element-plus/es/constants/index.mjs';
import { usePropsAlias } from './use-props-alias.mjs';
import { UPDATE_MODEL_EVENT, CHANGE_EVENT } from 'element-plus/es/constants/event.mjs';
  1. transfer/src/composables/use-check.mjs

原先为:

ts 复制代码
import { computed, watch } from 'vue';
import '../../../../utils/index.mjs';
import { CHECKED_CHANGE_EVENT } from '../transfer-panel.mjs';
import { usePropsAlias } from './use-props-alias.mjs';
import { isFunction } from '@vue/shared';

改为:

ts 复制代码
import { computed, watch } from 'vue';
import 'element-plus/es/utils/index.mjs';
import { CHECKED_CHANGE_EVENT } from '../transfer-panel.mjs';
import { usePropsAlias } from './use-props-alias.mjs';
import { isFunction } from '@vue/shared';
  1. transfer/src/transfer-panel2.mjs

原先为:

ts 复制代码
import { defineComponent, useSlots, reactive, computed, toRefs, openBlock, createElementBlock, normalizeClass, unref, createElementVNode, createVNode, isRef, withCtx, createTextVNode, toDisplayString, createBlock, createCommentVNode, withDirectives, Fragment, renderList, vShow, renderSlot } from 'vue';
import '../../../utils/index.mjs';
import '../../../hooks/index.mjs';
import { ElCheckbox, ElCheckboxGroup } from '../../checkbox/index.mjs';
import { ElInput } from '../../input/index.mjs';
import { Search } from '@element-plus/icons-vue';
import { transferPanelProps, transferPanelEmits } from './transfer-panel.mjs';
import './composables/index.mjs';
import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
import { useLocale } from '../../../hooks/use-locale/index.mjs';
import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
import { usePropsAlias } from './composables/use-props-alias.mjs';
import { useCheck } from './composables/use-check.mjs';
import { isEmpty } from '../../../utils/types.mjs';

改为:

ts 复制代码
import { defineComponent, useSlots, reactive, computed, toRefs, openBlock, createElementBlock, normalizeClass, unref, createElementVNode, createVNode, isRef, withCtx, createTextVNode, toDisplayString, createBlock, createCommentVNode, withDirectives, Fragment, renderList, vShow, renderSlot } from 'vue';
import 'element-plus/es/utils/index.mjs';
import 'element-plus/es/hooks/index.mjs';
import { ElCheckbox, ElCheckboxGroup } from 'element-plus/es/components/checkbox/index.mjs';
import { ElInput } from 'element-plus/es/components/input/index.mjs';
import { Search } from '@element-plus/icons-vue';
import { transferPanelProps, transferPanelEmits } from './transfer-panel.mjs';
import './composables/index.mjs';
import _export_sfc from 'element-plus/es/_virtual/plugin-vue_export-helper.mjs';
import { useLocale } from 'element-plus/es/hooks/use-locale/index.mjs';
import { useNamespace } from 'element-plus/es/hooks/use-namespace/index.mjs';
import { usePropsAlias } from './composables/use-props-alias.mjs';
import { useCheck } from './composables/use-check.mjs';
import { isEmpty } from 'element-plus/es/utils/types.mjs';
  1. transfer/src/transfer-panel.mjs

原先为:

ts 复制代码
import '../../../utils/index.mjs';
import { transferProps, transferCheckedChangeFn } from './transfer.mjs';
import { buildProps, definePropType } from '../../../utils/vue/props/runtime.mjs';

改为:

ts 复制代码
import 'element-plus/es/utils/index.mjs';
import { transferProps, transferCheckedChangeFn } from './transfer.mjs';
import { buildProps, definePropType } from 'element-plus/es/utils/vue/props/runtime.mjs';

改到这里,项目启动就不会报错了。

开始魔改

此刻你在transfer的代码里做的修改,都会体现在界面上。

回到一开始的需求,给每个option添加额外的文字,打开transfer/src/transfer2.mjs

将一下代码:

ts 复制代码
const optionRender = computed(() => (option) => {
      if (props.renderContent)
        return props.renderContent(h, option);
      if (slots.default)
        return slots.default({ option });
      return h("span", option[propsAlias.value.label] || option[propsAlias.value.key]);
    });

改为:

ts 复制代码
const optionRender = computed(() => (option) => {
      if (props.renderContent)
        return props.renderContent(h, option);
      if (slots.default)
        return slots.default({ option });
      return h("span", option[propsAlias.value.label] + '哇哈哈哈,我来啦' || option[propsAlias.value.key]);
    });

就有对应的修改啦

总结

其实你在引入transfer作为自定义组件时,会报很多错误,一点点的改就好啦。

看到这里的看官,麻烦点个赞赞哇

相关推荐
桂月二二27 分钟前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062062 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb2 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角2 小时前
CSS 颜色
前端·css
浪浪山小白兔3 小时前
HTML5 新表单属性详解
前端·html·html5
lee5763 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579653 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
limit for me4 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者4 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
qq_392794484 小时前
前端缓存策略:强缓存与协商缓存深度剖析
前端·缓存