在Vue.js项目中,表单是与用户交互的重要部分,特别是在需要动态管理表单项的场景下,如何优雅地实现添加、删除、上移、下移及验证功能变得尤为重要。本文将详细介绍如何使用Element UI来实现一个包含动态表单项管理以及验证功能的表单。
效果图如下
一、项目背景
假设我们正在开发一个活动管理系统,其中一个功能是为活动添加多条路线信息,每条路线包含路线名称、可参加人数和路线详情。用户需要能够动态地添加、删除、调整路线顺序,并且需要对所有表单项进行验证。
二、实现步骤
-
项目初始化
首先,确保你的Vue项目已经安装了Element UI。如果未安装,可以通过以下命令进行安装:npm install element-ui --save
然后在main.js中引入Element UI:
import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI);
-
模板结构
在组件的template部分,使用Element UI的el-form、el-descriptions、el-row、el-col、el-form-item、el-input等组件来构建表单。特别地,使用v-for指令来动态渲染表单项,并使用slot插槽来添加“新增”按钮。<template> <!-- 省略了部分代码,详细代码见文末 --> </template>
-
数据定义
在data函数中定义表单数据form和验证规则rules。form中包含activityTravelLines数组,用于存储路线信息。rules中定义了表单项的验证规则。
data() { return { form: { activityTravelLines: [ { name: "", limitNumber: "", lineDetail: "", rulesId: 0, }, ], //其他字段 }, arrayFieldRulesId: 0, rules: { //其他验证规则 }, }; },
-
初始化数据
在created钩子中,调用initData方法初始化数据。如果有初始化数据(如通过接口获取),则遍历activityTravelLines数组,为每一项添加rulesId,并更新验证规则。created() { this.initData(); this.updateRules(); // 更新验证规则 }, methods: { initData() { // 省略了部分代码,详细代码见文末 }, // 其他方法... }
-
动态管理表单项
提供addItem、removeItem、moveUp、moveDown方法来实现表单项的添加、删除、上移、下移功能。每次操作后,都需要调用updateRules方法来更新验证规则。methods: { // 省略了部分代码,详细代码见文末 addItem() { // 省略了部分代码,详细代码见文末 }, removeItem(index) { // 省略了部分代码,详细代码见文末 }, moveUp(index) { // 省略了部分代码,详细代码见文末 }, moveDown(index) { // 省略了部分代码,详细代码见文末 }, // 其他方法... }
-
表单验证
在submit方法中,使用this.$refs.form.validate方法来验证表单。如果验证通过,则执行提交操作。methods: { // 省略了部分代码,详细代码见文末 submit() { this.$refs["form"].validate((valid) => { if (valid) { //你的提交代码 console.log(this.form, "提交form表单"); } }); }, }
-
样式定义
使用SCSS来定义表单的样式,确保表单项之间的间距和布局合理。<style lang="scss" scoped> .btnCont { display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; .titleIndexCont { font-family: PingFang SC, PingFang SC; font-weight: 400; font-size: 20px; color: #333333; } } </style>
三、完整代码
<template>
<div class="container">
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-descriptions title="路线信息" :column="2">
<template slot="extra">
<el-button type="primary" @click="addItem" size="mini"
>新 增</el-button
>
</template>
</el-descriptions>
<div
v-for="(item, index) in form.activityTravelLines"
:key="item.rulesId"
>
<div class="btnCont">
<div class="titleIndexCont">
{{ "路线" + (index + 1) }}
</div>
<div>
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="removeItem(index)"
></el-button>
<el-button
type="success"
icon="el-icon-top"
size="mini"
@click="moveUp(index)"
></el-button>
<el-button
type="success"
icon="el-icon-bottom"
size="mini"
@click="moveDown(index)"
></el-button>
</div>
</div>
<el-row>
<el-col :span="12">
<el-form-item
label="路线名称:"
:prop="`activityTravelLines.${index}.name`"
>
<el-input v-model="item.name"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="可参加人数"
:prop="`activityTravelLines.${index}.limitNumber`"
>
<el-input
v-model="item.limitNumber"
type="number"
:min="0"
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item
label="路线详情:"
:prop="`activityTravelLines.${index}.lineDetail`"
>
<el-input
v-model="item.lineDetail"
type="textarea"
placeholder="请输入内容"
maxlength="300"
:rows="5"
show-word-limit
></el-input>
</el-form-item>
</div>
<!-- 其他el-form-item -->
</el-form>
<div class="footer">
<el-button type="primary" @click="submit">确 定</el-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
form: {
activityTravelLines: [
{
name: "",
limitNumber: "",
lineDetail: "",
rulesId: 0,
},
],
//其他字段
},
arrayFieldRulesId: 0,
rules: {
//其他验证规则
},
};
},
created() {
this.initData();
this.updateRules(); // 更新验证规则
},
mounted() {},
methods: {
initData() {
//如果有初始化数据,要遍历form.activityTravelLines,在每一项里面添加rulesId
if (this.id) {
//假设getTravelDetail是你的详情接口
getTravelDetail(this.id).then((res) => {
this.form = res?.data ?? {};
this.form.activityTravelLines = res?.data?.activityTravelLines ?? [];
this.form.activityTravelLines.map((item, index) => {
item.rulesId = index;
});
this.arrayFieldRulesId = this.form.activityTravelLines.length - 1;
this.updateRules(); // 更新验证规则
});
}
},
// 添加表单项
addItem() {
this.arrayFieldRulesId++;
this.form.activityTravelLines.push({
name: "",
limitNumber: "",
lineDetail: "",
rulesId: this.arrayFieldRulesId,
});
this.updateRules(); // 更新验证规则
},
// 删除表单项
removeItem(index) {
if (this.form.activityTravelLines.length == 1) {
this.$message({ message: "不能小于一条路线", type: "warning" });
return;
}
this.form.activityTravelLines.splice(index, 1);
this.updateRules(); // 更新验证规则
},
// 上移表单项
moveUp(index) {
if (index > 0) {
const movedItem = this.form.activityTravelLines.splice(index, 1)[0];
this.form.activityTravelLines.splice(index - 1, 0, movedItem);
this.updateRules(); // 更新验证规则
}
},
// 下移表单项
moveDown(index) {
if (index < this.form.activityTravelLines.length - 1) {
const movedItem = this.form.activityTravelLines.splice(index, 1)[0];
this.form.activityTravelLines.splice(index + 1, 0, movedItem);
this.updateRules(); // 更新验证规则
}
},
// 更新验证规则
updateRules() {
// 为每个表单项添加验证规则
this.form.activityTravelLines.forEach((item, index) => {
this.rules[`activityTravelLines.${index}.name`] = [
{ required: true, message: "路线名称不能为空", trigger: "blur" },
];
this.rules[`activityTravelLines.${index}.limitNumber`] = [
{ required: true, message: "可参加人数不能为空", trigger: "blur" },
];
});
},
submit() {
this.$refs["form"].validate((valid) => {
if (valid) {
//你的提交代码
console.log(this.form, "提交form表单");
}
});
},
},
};
</script>
<style lang="scss" scoped>
.btnCont {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 5px;
.titleIndexCont {
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 20px;
color: #333333;
}
}
</style>
四、总结
本文详细介绍了如何在Vue.js项目中使用Element UI实现一个包含动态表单项管理以及验证功能的表单。通过动态渲染表单项、管理表单项的顺序、以及进行表单验证,我构建了一个灵活且功能强大的表单组件。希望这篇文章能帮助你在项目中更好地处理类似的需求。