官方参考地址
业务场景:添加问卷问题,一共两类,选择题或简答题
一、代码示例
<!--questionData 是请求回去的数据-->
<template>
<a-form :label-col="{ span: 5 }"
:wrapper-col="{ span: 14 }"
:form="form">
<a-form-item label="序号">
{{isEdit?questionIndex:questionData.questionList?questionData.questionList.length+1:1}}
</a-form-item>
<a-form-item label="类型">
<a-select v-decorator="['currentType',{initialValue:2}]"
:disabled="forbidSelect">
<a-select-option :value=1>
选择题
</a-select-option>
<a-select-option :value=2>
文本题
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="是否必填">
<a-switch v-decorator="['currentRequired', { valuePropName: 'checked' }]" />
</a-form-item>
<a-form-item label="标题">
<a-input :maxLength="51"
v-decorator="['title',{
rules:[
{required: true, message: '请输入问卷标题'},
{ validator: lengthLimit(50, '字符过长,1~50个字符'),}
]
}]"></a-input>
</a-form-item>
<div v-if="form.getFieldValue('currentType') === 1">
<a-form-item v-for="(k, index) in form.getFieldValue('keys')"
:key="k"
v-bind="index === 0 ? formItemLayout : formItemLayoutWithOutLabel"
:label="index === 0 ? '选项' : ''"
:required="true">
<a-input :maxLength="21" v-decorator="[
`names[${k}]`,
{
validateTrigger: ['change', 'blur'],
rules: [
{
required: true,
whitespace: true,
message: '请输入选项名称',
},
{ validator: lengthLimit(20, '字符过长,1~20个字符'),}
],
},
]"
placeholder="选项名称"
style="width: 60%; margin-right: 8px" />
<a-icon v-if="form.getFieldValue('keys').length > 1"
class="dynamic-delete-button"
type="minus-circle-o"
:disabled="form.getFieldValue('keys').length === 1"
@click="() => remove(k)" />
</a-form-item>
<a-button type="primary"
@click="addOption"
style="margin-left:120px">选项添加</a-button>
</div>
</a-form>
<a-button @click="handleCancel">
取消
</a-button>
<a-button type="primary"
@click="handleSubmit()">
确定
</a-button>
</template>
<style lang="less" scoped>
.dynamic-delete-button {
cursor: pointer;
position: relative;
top: 4px;
font-size: 24px;
color: #999;
transition: all 0.3s;
}
.dynamic-delete-button:hover {
color: #777;
}
.dynamic-delete-button[disabled] {
cursor: not-allowed;
opacity: 0.5;
}
</style>
<script lang="ts">
import { Vue, Watch } from 'vue-property-decorator';
export default class SurveyEdit extends Vue {
form: any;
title = '新增问题';
isEdit = false;
//新增问题的用于展示问题序号
questionIndex: any;
// 是否必填
currentRequired = false;
// 添加选项的参数
choiceIndex = 0;
// 问题id
questionId: any;
formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 5 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 18 },
},
};
formItemLayoutWithOutLabel = {
wrapperCol: {
xs: { span: 24, offset: 0 },
sm: { span: 18, offset: 5 },
},
};
// 禁止修改类型标识 当为修改操作时,题目类型不改修改
forbidSelect = false;
@Watch('isEdit')
onChangeValue(newVal: boolean) {
this.title = newVal ? '编辑问卷' : '新增问卷';
this.forbidSelect = newVal ? true : false;
}
created() {
//创建form
this.form = this.$form.createForm(this, {
name: 'dynamic_form_item',
// 用于判断修改后,当前页面是否保存
// onFieldsChange: (v: any, r: any) => {
// this.unSave = true;
//},
});
// 这个动态创建表单项的初始化
this.form.getFieldDecorator('keys', { initialValue: [], preserve: true });
//获取 数据函数,自己按具体请求添加
this.getDetail();
}
//点击添加问题 展开添加选项弹窗
addQuestion() {
this.visible = true;
// 清空已有选项值
// 不知为何已经在弹窗关闭时,已经 this.form.resetFields();重置过数据,但还是不行,所有在打开弹窗时,又再单独重置了keys
this.form.setFieldsValue({
keys: [],
});
}
// 添加选择项
addOption() {
const { form } = this;
const keys = form.getFieldValue('keys');
const nextKeys = keys.concat(this.choiceIndex++);
form.setFieldsValue({
keys: nextKeys,
});
}
// 删除选择项
remove(k: any) {
const { form } = this;
const keys = form.getFieldValue('keys');
if (keys.length === 1) {
return;
}
form.setFieldsValue({
keys: keys.filter((key: any) => key !== k),
});
}
// 确认添加
async handleSubmit() {
// 校验数据规范
await this.form.validateFields();
//获取表单数据
const value = this.form.getFieldsValue();
const item = {
title: value.title,
type: value.currentType,
// 这是我根据后台传参要求编辑的,具体情况自行修改
isRequired: value.currentRequired ? 1 : 0,
};
// 选择题
if (value.currentType === 1) {
if (!value.names) {
this.$message.error('请添加选择!');
return;
} else {
// 过滤删除选项时产生的empty项
const filterArr = value.names.filter((item: any) => item);
if (!filterArr.length) {
this.$message.error('请添加选择!');
return;
} else {
Object.assign(item, {
optionsList: filterArr,
});
}
}
}
// 关闭modal
this.visible = false;
// 重置标题判断标识
this.isEdit = false;
//添加完后要把选项index 重新置为0
this.choiceIndex = 0;
// 清空表单数据
this.form.resetFields();
// 重新获取数据
this.getDetail();
}
// 取消添加
handleCancel() {
this.visible = false;
this.isEdit = false;
this.choiceIndex = 0;
this.form.resetFields();
}
// 编辑问题 questionItem就是上面添加项的数据(item)
linkToEdit(questionItem: any, index: number) {
this.isEdit = true;
this.visible = true;
this.questionId = questionItem.id;
// 设置表单数据
setTimeout(() => {
this.form.setFieldsValue({
title: questionItem.title,
currentRequired: questionItem.isRequired ? true : false,
currentType: questionItem.type,
});
}, 100);
//有这个代表是选择题
if (questionItem.optionsList) {
// 生成 选择项的 key
const keys = questionItem.optionsList.map(
(item: any, index: any) => index,
);
// 动态添加项的初始化
this.form.getFieldDecorator('keys', {
initialValue: keys,
preserve: true,
});
// 初始化添加项的index
this.choiceIndex = questionItem.optionsList.length ;
// 添加定时器,延时加载,不然会warning,同时选择值无法正常显示
setTimeout(() => {
this.form.setFieldsValue({
keys,
names: questionItem.optionsList,
});
}, 100);
// 要展示问题的序号
this.questionIndex = index;
}
}
</script>
二、相关问题及解决
2.1 动态添加选择题选项时,获取的选项数组有问题,导致渲染有问题
//获取表单数据
const value = this.form.getFieldsValue();
// 过滤删除选项时产生的empty项
const filterArr = value.names.filter((item: any) => item);
2.2 编辑时如何复现动态选择项数据
// 1. 生成 选择项的 key
const keys = questionItem.optionsList.map(
(item: any, index: any) => index,
);
// 2. 动态添加项的初始化
this.form.getFieldDecorator('keys', {
initialValue: keys,
preserve: true,
});
// 添加定时器,延时加载,不然会warning,同时选择值无法正常显示
setTimeout(() => {
// 3. 设置keys、names的值
this.form.setFieldsValue({
keys,
names: questionItem.optionsList,
});
}, 100);
}
// 4. 添加项的起始index
this.choiceIndex = questionItem.optionsList.length;
2.3 渲染问题
因为动态添加表单的项不像title
,是确定的表单项,所以会报错
warning.js:34 Warning: You cannot set a form field before rendering a field associated with the value. You can use
getFieldDecorator(id, options)instead
v-decorator="[id, options]"to register it before render.
同时渲染也会出现问题
解决方案:
通过setTimeout
延时加载解决
setTimeout(() => {
this.form.setFieldsValue({
keys: keys,
names: questionItem.optionsList,
});
}, 100);