javascript - 在 vue 中为创建表单处理数据层次结构的最佳方法
问题描述
假设我正在创建一个允许教师为学生创建作业的 vue.js 应用程序。每个作业都由介绍性文本和练习列表组成。每个练习也由文本和附件列表组成。
我想从充分利用 Vue 组件的角度来弄清楚创建表单以添加作业的最佳方式是什么。
假设实体被表示为具有以下结构的对象:
assignment: {
text: string,
dueDate: Date,
exercises: array
}
exercise: {
text: string,
attachments: array
}
attachment: {
text: string
}
完成创作形式的最天真的方法是拥有这样的东西:
// in <template>
<input type="text" v-model="assignment.text" />
<button @click="addExercise()">Add exercise</button>
<div v-for="exercise in assignment.exercises">
<input type="text" v-model="exercise.text" />
<button @click="addAttachment(exercise)">Add attachment</button>
<div v-for="attachment in exercise.attachments">
<input type="text" v-model="attachment.text" />
</div>
</div>
<button @click="submit()">Create assignment</button>
// in <script>
data() {
return {
assignment: {
text: '',
exercises: [],
}
}
},
methods() {
addExercise() {
this.assignment.push({
text: '',
attachments: [],
})
},
addAttachment(exercise) {
exercise.attachments.push({
text: '',
})
}
}
但这非常不雅,因为您将所有内容都转储到单个组件中。
我能想到的第一件事就是有AssignmentForm.vue
,ExerciseForm.vue
和AttachmentForm.vue
.
这样我就可以分别处理每个实体的数据和表单标记,并在我的主表单中组合所有内容。
但是,我不确定我将如何管理状态?我不能只是将子组件本地的所有内容复制到我的主窗体中,因为这没有任何意义。但与此同时,v-for
如果我没有一个结构来保存我的主要本地数据中的所有子表单,我将如何迭代我的 's?我还需要有一种方法来从我的子表单组件中收集所有数据,并将其组合成一个 json 对象,以便在提交表单时发送到我的后端。
你会怎么做?
解决方案
我使用 VeeValidate 嵌套数组解决了这个问题
文档示例非常基础,我在代码和box.io 上的示例项目中对其进行了扩展
- 代码 - https://codesandbox.io/s/frosty-microservice-72o2s?file=/src/App.vue
- 视频 - https://www.youtube.com/watch?v=iUN357fOUN0
我们有一个看起来像这样的最终对象
{
"group-name": "ewqqeeqw",
"members": [
{
"name": "aaron smith",
"email": "aarons@gmail.com"
},
{
"name": "aaron jones",
"email": "aaronj@gmail.com"
},
{
"name": "aaron key",
"email": "aaronk@gmail.com"
}
]
}
我从 vee validate 中获得的好处是状态管理和字段验证都提供了开箱即用的功能。我需要做的就是将项目添加到数组中,然后根据循环生成表单字段
<div>
<ion-label>MEMBERS</ion-label>
<div v-for="(m, index) in values.members" :key="index">
<div>
<ion-item>
<Field
as="ion-input"
type="text"
placeholder="name"
:name="`members[${index}].name`"
rules="required|min:8"
/>
</ion-item>
<span class="error">
{{ errors[`members[${index}].name`]?.split(".")[1] }}</span
>
<ion-item>
<Field
as="ion-input"
type="email"
placeholder="email"
:name="`members[${index}].email`"
rules="required|email"
/>
</ion-item>
<span class="error">
{{ errors[`members[${index}].email`]?.split(".")[1] }}</span
>
</div>
<ion-button
@click="removeMember(index, values)"
style="zoom: 0.7; margin-bottom: 8px"
>
REMOVE MEMBER
</ion-button>
</div>
</div>
<div style="padding-top: 12px">
<ion-button type="submit">SUBMIT</ion-button>
<ion-button @click="addMember(values)">ADD MEMBER</ion-button>
</div>
推荐阅读
- roku - Roku Scenegraph SGDEX - 替换 HDPosterURL 变量
- php - 当分隔符有效时,explode() 偏移量和分隔符警告
- java - 无法在 wsimport 生成的源中获取具有类路径方案的 URL 的资源
- spring-boot - Spring Boot JPA 更新失败
- python - 如何为列中的每个不同值转发重采样
- php - 我已经设置了 web 和 api 防护,但使用护照登录总是访问 web 防护
- javascript - 如果数据设置为假值(null、false、未定义等),为什么 v-bind:style 不会对更改做出反应
- javascript - css square限制大小和位置到父div
- flutter - 如何更改颤动中的文本选择选项?
- python - 使用 selenium 截屏时如何关闭网站弹出窗口?