一、问题阐述:动态表单的渲染
举例如下:根据
类型
显示标题后面的表单项渲染。
二、解决方法及注意事项
-
el-form-item
循环 的数组必须在el-form
绑定的表单中; -
el-form-item
的prop
需要是变量; - 当
el-form-item
的rules
也是变量时,需要判断是否必填项的情况下,然后使用相应的rules规则。
<el-form ref="formRef" :model="dynamicForm" label-width="120px">
<el-form-item
v-for="(item, index) in dynamicForm.optList"
:key="item.key"
:label="'item' + index"
:prop="'optList[' + index + '].value'"
:rules="item.required=='1' ? hasRules : noRules "
>
<el-input v-model="item.value"></el-input>
<el-button class="mt-2" @click.prevent="remove(item)"
>Delete</el-button
>
</el-form-item>
</el-form>
setup(){
const dataSet = reactive({
dynamicForm:{
optList:[] // 这个数组一定要在form绑定的表单里
},
hasRules: [{ required:true, message: '必填' }],
noRules:[{ required: false, message: '不必填' }],
})
}
三、动态表单项 - 多张图片上传方法一: 手动上传一次请求
由于elementPlus不支持一次请求上传多个文件,所以需要手动上传实现,代码如下:
<div v-for="(item,index) in addform.attach_content.sort" :key="item.id">
<el-form-item
v-for="(child,childIndex) in item.fields"
:key="child.id"
:label="child.name"
:prop="'attach_content.sort[' +index + '].fields[' + childIndex +'].value'"
:required="child.required==1 ? true:false"
:rules="child.required=='1' ? (child.type=='upload' ? uploadRules :tempBlurRules) : tempChangeRules "
>
<el-upload class="dl-avatar-uploader-min square"
v-if="child.type=='upload'"
ref="uploadMulti"
:action="uploadUrlMulti"
:limit="child.max"
:on-change="(file, fileList)=>{return fileChange(file, fileList, index, childIndex)}"
:on-remove="(file, fileList)=>{return fileRemove(file, fileList, index, childIndex)}"
:on-exceed="handleExceedTempImgM"
:file-list="child.fileList"
list-type="picture-card"
accept="image/*"
multiple
:auto-upload="false"
>
<el-button type="text">选择图片</el-button>
</el-upload>
<div class="mt10" v-if="child.type=='upload'">
<el-button type="primary" @click="submitUpload(index, childIndex)">确认上传</el-button>
<span class="red-star ml5">最多可上传 {{ child.max }} 张</span>
</div>
</el-form-item>
</div>
/*
* 由于数据嵌套层级较多,所以需要记录每一层的index值(index, childIndex)
*/
fileChange(file, fileList, index, childIndex) {
let postTemps = dataSet.addform.attach_content.sort;
postTemps[index].fields[childIndex].fileList = fileList;
},
fileRemove(file, fileList, index, childIndex) {
let postTemps = dataSet.addform.attach_content.sort;
postTemps[index].fields[childIndex].fileList = fileList;
},
submitUpload(index,childIndex){
let postTemps = dataSet.addform.attach_content.sort;
let imgList = postTemps[index].fields[childIndex].fileList;
let formData = new FormData(); // 将文件封装进FormData
if(imgList.length>0){
imgList.forEach(file => {
formData.append('files[]', file.raw)
})
// 调用上传接口
upMultiImg(formData).then((res) => {
//手动上传无法触发成功或失败的钩子函数,因此需要手动调用
console.log(res);
if(res.code==0){
postTemps[index].fields[childIndex].value = res.data.imgUrl.toString();
dataSet.imgupLoadFlag = true;
}else{
dataSet.imgupLoadFlag = false;
ElMessage.error({
message: res.msg,
type: "error",
});
}
})
}else{
ElMessage.error({
message: '请先选择图片!',
type: "error",
});
}
},
handleExceedTempImgM(files, fileList){
ElMessage.error({
message: `上传图片数量超出限制!`,
type: "error",
});
},
四、动态表单项 - 多张图片上传方法一: 自动上传多次请求
<div v-for="(item,index) in addform.attach_content.sort" :key="item.id">
<el-form-item
v-for="(child,childIndex) in item.fields"
:key="child.id"
:label="child.name"
:prop="'attach_content.sort[' +index + '].fields[' + childIndex +'].value'"
:required="child.required==1 ? true:false"
:rules="child.required=='1' ? tempBlurRules : tempChangeRules "
>
<el-upload class="dl-avatar-uploader-min square"
v-if="child.type=='upload'"
ref="uploadMulti"
:action="uploadUrl"
:limit="child.max"
:on-success="(response,file, fileList)=>{return fileSuccess(response, file, fileList, index, childIndex)}"
:on-remove="(file, fileList)=>{return fileRemove(file, fileList, index, childIndex)}"
:on-exceed="handleExceedTempImgM"
:file-list="child.fileList"
list-type="picture-card"
accept="image/*"
multiple
>
<el-button type="text">选择图片</el-button>
</el-upload>
</el-form-item>
</div>
/*
* 上传后的图片链接保存在fileListUp字段中
*/
fileSuccess(response, file, fileList, index, childIndex) {
if(response.code==0){
let obj = {};
obj.name = file.name;
obj.url = response.data.url;
dataSet.addform.attach_content.sort[index].fields[childIndex].fileListUp.push(obj);
}else{
ElMessage.error({
message: response.msg,
type: "error",
});
}
},
fileRemove(file, fileList, index, childIndex) {
let postTemps = dataSet.addform.attach_content.sort;
let picArr = postTemps[index].fields[childIndex].fileListUp;
picArr.forEach((item, index) => {
if (file.name == item.name) {
picArr.splice(index, 1);
}
});
},
handleExceedTempImg(files, fileList){
ElMessage.error({
message: `上传图片数量超出限制!`,
type: "error",
});
},
五、后记
手动上传与自动上传,各有各的优缺点;以下分析是在动态增减表单项的前提下
手动上传:缺点:选择完图片后,必须再点确认上传按钮,无法在点击保存的时候执行上传图片操作;优点:无论传几张图,只请求一次
;
自动上传:缺点:需要多次请求上传;优点:无感上传
,无需多余操作;
六、关于添加修改共用表单,清空问题
点击修改时,给表单赋值,在点添加,表单项调用了清空函数,但并未清空;
解决:编辑时赋值放在nextTick里
add(){
addformid.value.resetFields();
dataSet.isUpdate = false;
dataSet.addDialog = true;
},
// 编辑
edit(row){
dataSet.isUpdate = true;
dataSet.addDialog = true;
nextTick(()=>{ // 放在true后,nexttick里
dataSet.addform = row;
dataSet.editId = row.id;
})
},