element-plus: 二次封装el-form方案?

网上看了几篇文章,都不是想要的答案。于是给下自己的实现思路,各位有好的建议也可以评论。

建议直接看源码: https://github.com/jyj1202/j-admin/blob/dev/src/views/j-form/components/JForm.vue

如果觉得有用,可以去github给我的项目点个star。

核心思路就是利用vue的动态组件渲染需要的组件,而不是v-if判断。这样大大简化了代码。

模板部分代码:

<el-form-item
          :label="col.label"
          :prop="col.prop"
          :rules="col.rules"
        >
          <slot :name="col.prop" v-bind="{col, size: getProp('size', col)}">
            <component
              :is="getComponentType(col, getProp('type', col))"
              v-model="formData[col.prop]"
              v-bind="getComponentProps(col)"
              :key="col.prop"
              @change="handleFormItemValueChange"
            >
              <template v-if="!col.component && getSlotComponent(getProp('type', col))">
                <!-- 目前只有两种情况
                1.有dicData的formItem
                2.upload组件里的button
                -->
                <template v-if="col.dicData">
                  <component
                    v-for="dicData in col.dicData"
                    :key="dicData.value"
                    :is="getSlotComponent(getProp('type', col))"
                    v-bind="dicData"
                  />
                </template>
                <el-button
                  v-if="getSlotComponent(getProp('type', col))=='el-button'"
                  type="primary"
                >Click to upload
                </el-button>
              </template>
            </component>
          </slot>
        </el-form-item>

需要注意的是,涉及到有插槽的组件,我目前的思路是:

1.条件判断,渲染对应的插槽内组件。

/**
 * @description 获取组件插槽内子组件
 * @param type 
 */
const getSlotComponent = (type: string): string|undefined => {
  /* 插槽子组件映射 */
  const slotCompMap: Record<string, string> = {
    'select': 'option',
    'radio-group': 'radio',
    'checkbox-group': 'checkbox',
    'upload': 'button'
  }
  return `el-${slotCompMap[type]}`
}

2.二次封装该组件,用props配置项取代插槽,然后使用二次封装后的组件。

3.使用jsx写法,灵活的渲染插槽,但是需要用户传入插槽对应的jsx,提高了用户使用复杂度。

用户传入的表单配置数据解构:

const formOption = reactive<JFormOptionType>({
  labelPosition: 'left',
  column: [{
    label: 'input',
    prop: 'input',
    type: 'input',
    span: 8,
    placeholder: 'try to input something',
    rules: {
      required: true,
      message: "Please input something",
      trigger: "blur"
    }
  }, {
    label: 'input-number',
    prop: 'input-number',
    type: 'input-number',
    min: 1,
    max: 2,
    span: 8,
  }, {
    label: 'password',
    prop: 'password',
    type: 'password',
    showPassword: true,
    span: 8
  }, {
    label: 'select',
    prop: 'select',
    type: 'select',
    multiple: true,
    placeholder: 'make a selection',
    rules: [{
      required: true,
      message: "Please select something",
      trigger: "blur"
    }],
    dicData: [{
      label: 'select1',
      value: 0
    }, {
      label: 'select2',
      value: 1
    }]
  }, {
    label: 'switch',
    prop: 'switch',
    type: 'switch',
    inlinePrompt: true,
    activeIcon: "Check",
    inactiveIcon: "Close",
  }, {
    label: 'radio-group',
    prop: 'radioGroup',
    type: 'radio-group',
    rules: {
      required: true,
      message: "Please select something",
      trigger: "blur"
    },
    dicData: [{
      label: 'radio1',
      value: 0
    }, {
      label: 'radio2',
      value: 1
    }]
  }, {
    label: 'checkbox-group',
    prop: 'checkbox-group',
    type: 'checkbox-group',
    dicData: [{
      label: 'checkbox1',
      value: 0
    }, {
      label: 'checkbox2',
      value: 1
    }]
  }, {
    label: 'date-picker',
    prop: 'date-picker',
    type: 'date',
    rules: {
      required: true,
      message: "Please select date",
      trigger: "blur"
    },
  }, {
    label: 'rate',
    prop: 'rate',
    type: 'rate',
  }, {
    label: 'slider',
    prop: 'slider',
    type: 'slider',
    span: 24,
    formatTooltip: (val: number) => {
      return val / 100
    },
  }, {
    label: 'transfer',// FIXME:bug
    prop: 'transfer',
    type: 'transfer',
    span: 24,
    data: ref<{
      key: number
      label: string
      disabled: boolean
    }[]>([{
      key: 1,
      label: 'option 1',
      disabled: false
    }, {
      key: 2,
      label: 'option 2',
      disabled: true
    }, {
      key: 3,
      label: 'option 3',
      disabled: false
    }, ])
  }]
})

好的,下面我来尝试给您讲解一下如何基于若依框架使用vue3+element-plus去二次封装一个el-dialog: 1. 首先,在使用vue3+element-plus进行开发前,需要先安装对应的依赖。可以通过以下命令进行安装: ``` npm install vue@next npm install element-plus --save ``` 2. 接下来,我们需要创建一个新的dialog组件。可以在`components`文件夹下新建一个`dialog.vue`文件,然后在该文件中定义我们的dialog组件。 ```vue <template> <el-dialog :visible.sync="visible" :title="title" :width="width" :before-close="beforeClose"> <slot></slot> </el-dialog> </template> <script> import { defineComponent } from 'vue' import { ElDialog } from 'element-plus' export default defineComponent({ name: 'Dialog', components: { ElDialog, }, props: { visible: { type: Boolean, default: false, }, title: { type: String, default: '', }, width: { type: String, default: '50%', }, beforeClose: { type: Function, default: () => {}, }, }, }) </script> ``` 在`dialog`组件中,我们使用了`<el-dialog>`组件,并且对其进行了二次封装。我们将`visible`、`title`、`width`和`beforeClose`四个属性绑定到`<el-dialog>`组件上,同时在`<slot>`中插入了组件传递进来的内容。 3. 接下来,我们需要在使用dialog的页面中引入该组件,并且传递需要的参数。 ```vue <template> <div> <el-button @click="showDialog">打开dialog</el-button> <dialog :visible="dialogVisible" :title="dialogTitle" :beforeClose="beforeClose"> <el-form> <el-form-item label="姓名"> <el-input v-model="name"></el-input> </el-form-item> <el-form-item label="年龄"> <el-input v-model="age"></el-input> </el-form-item> </el-form> </dialog> </div> </template> <script> import { defineComponent, ref } from 'vue' import Dialog from '@/components/dialog.vue' export default defineComponent({ name: 'Page', components: { Dialog, }, setup() { const dialogVisible = ref(false) const dialogTitle = ref('示例dialog') const name = ref('') const age = ref('') const showDialog = () => { dialogVisible.value = true } const beforeClose = (done) => { if (name.value && age.value) { done() } else { this.$message.warning('请输入完整信息') } } return { dialogVisible, dialogTitle, name, age, showDialog, beforeClose, } }, }) </script> ``` 在`Page`页面中,我们引入了刚才定义的`<dialog>`组件,并且传递了需要的参数。在点击打开dialog的按钮时,我们通过`showDialog`方法来显示dialog。在dialog关闭前,我们通过`beforeClose`方法来进行校验,只有当输入完整信息时才能关闭dialog。 至此,我们就完成了基于若依框架使用vue3+element-plus去二次封装一个el-dialog的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值