在vue3中实现多类别表单的拆分和组合

421 阅读1分钟

问题:

假设现在你有5个类别的表单,每个表单都有几个公有属性,比如姓名,编号,时间等,除此之外每个类别都有其他几个私有属性,需要把公有的属性提取出来,之后整合字段数据提交表单。

具体实现方式如下:

在共有组件中,使用 reactive 函数创建一个响应式的 commonData 对象,将共有属性加入到该对象中。然后,将 commonData 对象、handleSubmit 方法和 slot 作为组件返回值,供子组件进行引入。

在子组件中,先使用 ref 函数创建一个响应式的选项对象 formData,将子组件的独有属性加入到该对象中。然后,在子组件模板中使用 v-model 绑定到 formData 对象中相应的属性上,并在 submitForm 方法中将 formData 对象和 commonData 对象使用对象浅合并的方式整合后,调用 handleSubmit 方法,将整合后的数据传递给共有组件的处理方法。

下面是示例代码:

(1)最外层组件:Demo.vue

<template>
  <Father>
    <FoodForm />
  </Father>
</template>

<script>
import { defineComponent, inject, provide, ref } from 'vue'
import Father from './Father.vue'
import FoodForm from './FootForm.vue'

export default defineComponent({
  components: {
    Father,
    FoodForm
  },
  setup(props, { slots }) {
    return {}
  }
})
</script>

(2)公有属性组件-Father.vue

   <template>
  <div>
    <div class="line-table">
      <label for="username">姓名:</label>
      <input type="text" id="username" v-model="commonData.userName" />
    </div>
    <div>
      <label for="id">编号:</label>
      <input type="text" id="id" v-model="commonData.id" />
    </div>
    <div>
      <label for="time">时间:</label>
      <input type="text" id="time" v-model="commonData.time" />
    </div>

    <!-- 插槽,用来放置子组件 -->
    <slot></slot>
  </div>
</template>

<script >
import { getCurrentInstance, defineComponent, provide, ref } from "vue";
import useFormComposable from "./formComposable";

export default defineComponent({
  setup() {

    const { commonData, handleSubmit } = useFormComposable();
    const slots = getCurrentInstance().slots;

    provide('Father', { handleSubmit })

    return {
      commonData,
      handleSubmit,
      slots,
    };
  },
})
</script>

<style scoped>
.line-table {
  display: flex;
  align-items: center;
}
</style>

formComposable.js

import { reactive } from 'vue'

export default function useFormComposable() {
	const commonData = reactive({
		userName: '',
		id: '',
		time: ''
	})
	const handleSubmit = data => {
		const formData = Object.assign(commonData, data)
		console.log('~~~11~~~整合数据', formData)
	}

	return {
		commonData,
		handleSubmit
	}
}

(3)子组件-私有属性组件-FootForm.vue

   <template>
  <div>
    <div>
      <label for="foodName">食品名称:</label>
      <input type="text" id="foodName" v-model="formData.foodName" />
    </div>
    <div>
      <label for="foodSize">食品大小:</label>
      <input type="text" id="foodSize" v-model="formData.foodSize" />
    </div>
    <button @click.prevent="submitForm">提交</button>
  </div>
</template>

<script>
import { defineComponent, ref, inject } from 'vue'

export default defineComponent({
  setup(props, { slots }) {

    const formData = ref({
      foodName: '',
      foodSize: ''
    })
    const { handleSubmit } = inject('Father') 

    const submitForm = () => {
      handleSubmit(formData.value)
    }

    return {
      formData,
      submitForm
    }
  }
})
</script>

(4)子组件2-私有属性组件-ProductForm.vue

    <!-- 子组件2 -->
    <template>
  <div>
    <div>
      <label for="foodName">食品名称:</label>
      <input type="text" id="foodName" v-model="formData.foodName" />
    </div>
    <div>
      <label for="foodSize">食品大小:</label>
      <input type="text" id="foodSize" v-model="formData.foodSize" />
    </div>
    <button @click.prevent="submitForm">提交</button>
  </div>
</template>

<script>
import { defineComponent, ref, inject } from 'vue'

export default defineComponent({
  setup(props, { slots }) {

    const formData = ref({
      foodName: '',
      foodSize: ''
    })
    const { handleSubmit } = inject('Father') 

    const submitForm = () => {
      handleSubmit(formData.value)
    }

    return {
      formData,
      submitForm
    }
  }
})
</script>