0
点赞
收藏
分享

微信扫一扫

小白的一次Form组件封装分享

Form组件介绍

form表单常用在回显表单信息 + 验证表单 + 提交表单信息。通常包含输入框, 选择框,日期选择框,文本框等可输入的组件。

封装思路

通过配置文件生成一个基本的表单,然后配合数据的双向绑定得到我们提交的数据,同时尽量保留第三方 UI 库组件提供的属性(Attributes)、插槽(Slots)和自定义事件(Events)

实现

1. 数据驱动

<template>
  <a-form
    :model="formState"
    name="basic"
    :label-col="{ span: 8 }"
    :wrapper-col="{ span: 16 }"
    autocomplete="off"
  >
    <a-form-item
      label="Username"
      name="username"
      :rules="[{ required: true, message: 'Please input your username!' }]"
    >
      <a-input v-model:value="formState.username" />
    </a-form-item>
    <a-form-item
      label="Password"
      name="password"
      :rules="[{ required: true, message: 'Please input your password!' }]"
    >
      <a-input-password v-model:value="formState.password" />
    </a-form-item>
    <a-form-item name="remember" :wrapper-col="{ offset: 8, span: 16 }">
      <a-checkbox v-model:checked="formState.remember">Remember me</a-checkbox>
    </a-form-item>
    <a-form-item :wrapper-col="{ offset: 8, span: 16 }">
      <a-button type="primary" html-type="submit">Submit</a-button>
    </a-form-item>
  </a-form>
</template>

  1. Form表单数据绑定在a-form上::model="form",form就是表单的数据对象。
  2. 表单里面的每一项是放在a-form-item标签里面,放入我们想渲染出来的组件,如输入框,选择框等。
  3. 每个a-form-item中可以绑定了label、rules等属性

通过分析Form代码我们可以通过一个配置文件去遍历a-form-item,然后在a-form-item上面绑定我们需要的属性,以及a-form-item标签里面各种输入组件。

这个配置文件应包括 label 标签的文本 name表单域 model 字段rules检验规则等表单的api,也应该包括内部可输入组件的api,比如类型(输入框、选择框、日期框等)

2.v-model实现父子组件双向数据绑定

原理: v-model绑定在组件上的时候做了以下步骤 在父组件内给子组件标签添加 v-model ,其实就是给子组件绑定了 value 属性 子组件内使用 props 拿到父组件传递下来的value。 子组件内部更改 value 的时候,必须通过 emit('update:value', e)更新父组件v-model绑定的变量

props 传值是单向的,即父组件中的数据改变会反映到子组件中,但在子组件内部不能主动改变 props的值,子组件中不能使用 v-model="modelValue" 之类方法试图直接改变父组件的值。

父组件 v-model传递的值的默认名称是modelValue,子组件通过props接收modelValue

<Ainput v-model="data" />

子组件

1.拆成:value='modelValue',监控子组件的更新事件触发emit('update:modelValue', e)

// 子组件
// 
<template>
  <div>
    <a-input :value="modelValue" v-bind="$attrs" @change="change" />
  </div>
</template>

<script lang="ts" setup name="AInput">
defineProps({
  modelValue: {
    type: String,
    default: '',
  },
})

const emit = defineEmits(['update:modelValue'])

// 更新modelValue
const change = (e: { target: HTMLInputElement }) => {
  emit('update:modelValue', e.target.value.trim())
}
</script>

  1. 通过计算属性computed的set/get实现双向绑定

// 子组件
<template>
  <div>
    <a-input v-model:value="modelValue" v-bind="$attrs" />
  </div>
</template>
<script lang="ts" setup name="AInput">
import { computed } from 'vue'

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  },
})

const emit = defineEmits(['update:modelValue'])

// 双向绑定
const formValue = computed({
   //get父组件的modelValue
  get: () => {
    return props.modelValue
  },
  // input更新formValue时触发set,set通过emit通知父组件更新modelValue
  set: (val) => {
    emit('update:modelValue', val)
    emit('getvalue', val, props.meta.colName)
  },
})
</script>

如果是对象的话可以使用vueuse的useVModel方法

<script lang="ts" setup>
import { useVModel } from '@vueuse/core'

const props = defineProps({
  //表单数据
  formData: {
    type: Object as PropType<ObjectExtends>,
    default: () => {
      return {}
    },
  },
})
const emit = defineEmits(['update:formData'])

// 实现双向绑定 每当 prop 发生变化时,model 就会改变。但只要它从这个组件中被改变,它就会发出update:formData, 通过父组件的v-model指令触发更新。
const model = useVModel(props, 'formData', emit)

</script>

3. Attributes透传

在 Vue 3.x 当中,通过v-bind$attrs属性就可以进行 props 属性和 event 事件的透传分发了。

$attrs透传属性包括props,events, class,style,id等。(不包含接收组件显式声明的 propsemits以及slots )

{
    title: 'input1',
    colName: 'input1',
    controlType: 100,
    rules: [{ required: true, message: 'input1不可为空' }],
    style: 'background: red',
    class: 'normalInput',
  },
// 子组件
<template>
  <div>
    <a-input v-model:value="modelValue" v-bind="$attrs" />
  </div>
</template>

如果不希望透传某些属性比如rules, 可以通过useAttrs来实现

// 子组件
<template>
  <div>
    <a-input v-model:value="modelValue" v-bind="filteredAttrs" />
  </div>
</template>
const attrs = useAttrs()
const filteredAttrs = computed(() => {
  return { ...attrs, rules: undefined }
})



举报

相关推荐

0 条评论