在这里插入图片描述

1. 封装组件DymanicForm.vue

  1. 使用component实现动态组件
  2. 组件不能直接使用字符串传入,所以根据传入的组件名称找到对应的组件
  3. 校验规则,可使用rule传入自定义规则,也可以使用封装好的基本规则 示例中使用了checkRequired
  4. 暴露重置方法和校验方法
<template>
  <el-form
    :model="currentValue"
    ref="dymanicForm"
    v-bind="$attrs"
    @submit.native.prevent
  >
    <el-form-item
      :prop="index"
      :rules="item.rules"
      v-for="(item, index) in currentSchema"
      :key="index"
      v-bind="item.formItem || {}"
    >
      <component
        v-model="currentValue[index]"
        :is="item.componentName"
        v-bind="item"
        v-on="item.methods || {}"
      />
    </el-form-item>
    <slot />
  </el-form>
</template>

<script lang="ts" setup>
import checkValidator from "~/utils/validator/index";

import {
  ElInput,
  ElSelect,
  ElDatePicker,
  ElCheckbox,
  ElRadio,
  ElRadioGroup,
  ElCheckboxGroup,
  ElSwitch,
} from "element-plus";

const componentMap = {
  ElInput: ElInput,
  ElSelect: ElSelect,
  ElDatePicker: ElDatePicker,
  ElCheckbox: ElCheckbox,
  ElRadio: ElRadio,
  ElRadioGroup: ElRadioGroup,
  ElCheckboxGroup: ElCheckboxGroup,
};

const props = defineProps({
  schema: Object,
  modelValue: [String, Number, Boolean, Array, Date, Object],
});
const emit = defineEmits(["update:modelValue"]);
const currentValue = computed({
  get: () => props.modelValue,
  set: (val) => emit("update:modelValue", val),
});

const currentSchema = computed(() => {
  const schema = {};
  for (const key in props.schema) {
    let { visible = true, ...item } = props.schema[key];
    // 动态表单的组件名
    item.componentName = componentMap[item.componentName];
    // 是否显示
    visible =
      typeof visible !== "function" ? visible : visible(currentValue, item);
    if (visible) {
      schema[key] = { clearable: true, ...item };
    }
    // 表单验证规则
    if (schema[key].validator && schema[key].validator.length) {
      if (!schema[key].rules) schema[key].rules = [];
      schema[key].validator?.forEach(([valida, args]) => {
        if (checkValidator[valida]) {
          schema[key].rules.unshift(checkValidator[valida](args));
        }
      });
    }
  }
  return schema;
});
const dymanicForm = ref(null);
const validate = (func) => {
  if (typeof func === "function") {
    dymanicForm.value.validate((valid) => {
      func(valid);
    });
  } else {
    return new Promise((resolve) => {
      dymanicForm.value.validate((valid) => {
        resolve(valid);
      });
    });
  }
};
const resetFields = () => {
  dymanicForm.value.resetFields();
};

defineExpose({
  resetFields,
  validate,
});
</script>

2. 调用组件示例

<template>
  <div class="">
    <DymanicForm
      ref="formRef"
      :inline="true"
      :schema="schema"
      v-model="searchValue"
    >
      <el-form-item>
        <el-button type="primary" @click="handleQuery">查询</el-button>
        <el-button @click="handleReset">重置</el-button>
      </el-form-item>
    </DymanicForm>
  </div>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import type { ItemSchema } from "~/types/dymanic";
import DymanicForm from "~/components/DymanicForm.vue";

const formRef = ref<InstanceType<typeof DymanicForm>>();
const schema = ref<ItemSchema>({
  userId: {
    formItem: {
      label: "用户ID:",
    },
    style: {
      width: "200px",
    },
    componentName: "ElInput",
    placeholder: "请输入用户ID",
    maxlength: 20,
    validator: [
      [
        "checkRequired",
        {
          msg: "用户ID不能为空",
        },
      ],
    ],
  },
  username: {
    formItem: {
      label: "账号:",
    },
    style: {
      width: "200px",
    },
    componentName: "ElInput",
    placeholder: "请输入账号",
    maxlength: 20,
  },
  name: {
    formItem: { label: "用户名:" },
    style: {
      width: "200px",
    },
    componentName: "ElInput",
    placeholder: "请输入用户名",
    maxlength: 20,
  },
});
const searchValue = reactive({
  userId: "",
  username: "",
  name: "",
});
const handleQuery = () => {
  formRef.value.validate((valid: boolean) => {
    if (valid) {
      console.log("查询", searchValue);
      // 查询逻辑
    }
  });
};

const handleReset = () => {
  formRef.value.resetFields();
};
</script>
<style lang="scss" scoped></style>

3. 校验规则示例

// 校验内容不能为空的验证
const checkRequired = ({ msg, trigger = ['blur'] }) => {
  return {
    required: true,
    message: msg,
    trigger,
  }
}

export default checkRequired

GitHub 加速计划 / eleme / element
54.06 K
14.63 K
下载
A Vue.js 2.0 UI Toolkit for Web
最近提交(Master分支:3 个月前 )
c345bb45 7 个月前
a07f3a59 * Update transition.md * Update table.md * Update transition.md * Update table.md * Update transition.md * Update table.md * Update table.md * Update transition.md * Update popover.md 7 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐