基于vue3的antd vue 2.x form组件之自定义表单项

2,464 阅读1分钟

前提

发现antd vue和element plus的官网都没有自定义表单项组件的文档, 参考老版本的文档写, 又无效, 经过一段时间的摸索, 终于有了一个有效的解决办法, 遂在此记录

定义自定义表单项组件

请一定要注意查看代码中的注释.

MyComp.vue

<template>
  <a-button @click="onClick">按钮</a-button>
  内部: {{ data }}
</template>

<script lang="ts">
import {defineComponent, ref, toRefs, watch} from "vue";

export default defineComponent({
  props: {
    // 注意: 这里之所以声明一个id, 是因为 ant design vue 2.x 的表单项组件会自动传传过来, 如果不定义, 那么控制台会出现一大片警告
    id: String,
    // 注意: 这里的value和update:value, 是构成 v-model:value的要素, 之所以用value而不是modelValue是为了和ant design vue2.x保持一致
    value: String
  },
  emits: {
    // 注意: 当定义了emits选项之后, 所有的context.emit的事件, 都应该在这里声明一次, 否则编译器会提示错误
    'update:value': (val: string) => {
      return true;
    },
    change: (val: string) => {
      return true;
    },
    // 如果作为ant design of vue的表单项如果没声明这个, 也会出现大片警告, 当前这个emit在这个组件中并未用上
    blur: (val: string) => {
      return true;
    }
  },
  setup(props, context) {
    const {value} = toRefs(props)
    const data = ref<string>()
    watch(value, () => {
      // 监听外部传入的value的变化, 将value的变化传递给data
      data.value = value.value
    })
    const onClick = () => {
      data.value = '张三'
      // 发出这个事件, 是为了触发vue的v-model, 执行双向绑定
      context.emit('update:value', data.value)
      // 发出这个事件, 是为了能够触发 ant design vue 的自定义验证
      context.emit('change', data.value)
    }
    return {onClick, data}
  }
})
</script>

Test.vue

<template>
  <a-form :model="formDataRef" ref="formRef">
    <a-form-item label="标题" name="title" :rules="nameRules">
      <a-input v-model:value="formDataRef.title"/>
    </a-form-item>
    <!-- 这里使用的就是自定义表单组件 -->
    <a-form-item label="我的值" name="myVal" :rules="myValRules">
      <MyComp v-model:value="formDataRef.myVal"></MyComp>
    </a-form-item>
  </a-form>
  <a-button @click="onClick">获取表单数据</a-button>
  <a-button @click="onChangeFormData">外部直接修改表单数据</a-button>
</template>

<script lang="ts">
import {defineComponent, reactive, ref, toRaw} from "vue";
import MyComp from "@/MyComp.vue";
import {RuleObject, ValidateErrorEntity} from "ant-design-vue/es/form/interface";

interface FormData {
  title: string,
  myVal: string
}

export default defineComponent({
  setup() {
    const formRef = ref();
    const formData: FormData = {title: '', myVal: ''}
    const formDataRef = reactive<FormData>(formData);
    const checkName = (rule: RuleObject, value: string) => {
      console.log('执行 checkName 验证', rule, value)
      return Promise.resolve();
    }
    const checkMyVal = (rule: RuleObject, value: string) => {
      console.log('执行 checkMyVal 验证', rule, value)
      return Promise.resolve();
    }
    const myValRules = [{
      trigger: 'change',
      validator: checkMyVal
    }]
    const nameRules = [{
      trigger: 'change',
      validator: checkName
    }]
    const onClick = () => {
      formRef.value
          .validate()
          .then(() => {
            const obj = toRaw(formDataRef)
            console.log('values', formDataRef, obj);
          })
          .catch((error: ValidateErrorEntity<FormData>) => {
            console.log('error', error);
          });
    }
    const onChangeFormData = () => {
      formDataRef.myVal = '改了myVal'
      formDataRef.title = '改了title'
      console.log('外部改变值formDataRef')
      // 直接修改 formDataRef.myVal 的值, 并不会自动触发 myVal的验证, 因此需要手动触发一次
      formRef.value.validateFields('myVal')
    }
    return {formRef, formDataRef, onClick, myValRules, nameRules, onChangeFormData}
  },
  components: {MyComp}
})
</script>

<style lang="less" scoped>

</style>