vue+vant动态渲染生成form表单生成多个上传插件(页面配置化)

15 篇文章 0 订阅

页面配置化,根据数据库配置,动态生成表单的上传组件。

后面有补充表单输入框、单选框、复选框、日期控件、下拉框(picker选择器)以及级联的动态渲染。

上传插件动态

从后端读取页面配置的表单信息,渲染到页面,这里是多个上传插件渲染了。

 

依次上传后,可以看到fileList也是对应的

 删除后也要对应的传给子组件

 上代码,省略样式和后端交互的逻辑

父组件

<template>

    <div>
        <van-form ref="uploadForm">
            <div v-for="(item,index) in currentFileList">
                <van-cell-group inset style="font-size:14px;">
                    <van-cell v-if="item.type=='pic'" style="padding-left:0;padding-top: 3px;">
                        <van-field colon   :required="item.required" :label="item.desc" :rules="[{required:`${item.required}`,message:`${item.placeHolder}`}]">
                            <template #input>
                                    <Upload :data="item" @getFileData="fileData"/>
                            </template>
                        </van-field>

                    </van-cell>

                </van-cell-group>
            </div>
        </van-form>
    </div>
</template>


<script>  
/*eslint-disable*/  
import Upload from './upload'
export default {
       name:'formDemo',
        data() {
            return {
                   dataForm:{},
				   currentFileList:[{
                    desc:'图片1',
                    type:'pic',
					infoName:"houseCert",
					placeHolder:"请上传xx文件",
					required:true,
                    multiple:true,
                    maxCount:3
				   
				   },{
                    desc:'图片2',
                    type:'pic',
					infoName:"shopCert",
					placeHolder:"请上传xx文件",
					required:false,
                    multiple:false,
                    maxCount:1
				   
				   }]
                }
        },
        components:{
            Upload
        },
		methods: {
			fileData(item){
				console.log("子组件的数据:"+item.infoName+":"+item.fileList.length);
				this.dataForm[item.infoName]=item.fileList;

			}
		}

}
</script>

子组件

<template>

    <div>
        <van-uploader
        v-model="fileList"
        :multiple="data.multiple"
        :max-count="data.maxCount"

        :after-read="(file)=>afterRead(file,data)"
        :before-delete="(file,detail)=>delImg(file,detail)"
        ref="uploadPic"
        />

    </div>
</template>



<script>    
    export default {
           props:{
            data:{
                type:Object,
                default:()=>{}
            }
           },
            data() {
                return {
                      fileList:[]
                    }
            },
           
            methods: {
                afterRead(file){
                    var item = this.data;
                    item.fileList = this.fileList;
                    //数据传给父组件
                    this.$emit('getFileData',item)
    
                },
                delImg(file,detail){
                    this.fileList.splice(detail.index,1);
                    var item = this.data;
                    item.fileList = this.fileList;
                    //数据传给父组件
                    this.$emit('getFileData',item)
                }
            }
    
    }
    </script>

父组件样式优化

<template>

    <div>
        <van-form ref="uploadForm">
            <div v-for="(item,index) in currentFileList">
                <van-cell-group inset style="font-size:14px;">
                    <van-cell v-if="item.type=='pic'" style="padding-left:0;padding-top: 3px;">
                      <!--  :required="item.required" :label="item.desc"--> 
                      <!--展示优化-->
                      <span style="color:red;margin-left:0.5rem">{{item.required?'*  ':''}}</span>{{item.desc}}
                      <span style="color:#cccccc;margin-left:0.2rem;font-size:12px;">{{item.tip}}</span>
                        <van-field :rules="item.required?[{required:`${item.required}`,message:`${item.placeHolder}`}]:[]">
                            <template #input>
                                    <Upload :data="item" @getFileData="fileData"/>
                            </template>
                        </van-field>

                    </van-cell>

                </van-cell-group>
            </div>
            <div>
              <van-button style="width:80%;margin-left:2rem;" type="danger" round @click="submit()">提交</van-button>
            </div>
        </van-form>
    </div>
</template>


<script>  
/*eslint-disable*/  
import Upload from './upload'
export default {
       name:'formDemo',
        data() {
            return {
                   dataForm:{},
				           currentFileList:[{
                    desc:'图片1',
                    type:'pic',
                    infoName:"houseCert",
                    placeHolder:"请上传xx文件",
                    required:true,
                    multiple:true,
                    maxCount:3,
                    tip:'请按页逐张上传'
				   
				   },{
                    desc:'图片2',
                    type:'pic',
                    infoName:"shopCert",
                    placeHolder:"请上传xx文件",
                    required:false,
                    multiple:false,
                    maxCount:1,
                    tip:'非必传'
              
				   
				   }]
                }
        },
        components:{
            Upload
        },
		methods: {
			fileData(item){
				console.log("子组件的数据:"+item.infoName+":"+item.fileList.length);
				this.dataForm[item.infoName]=item.fileList;

			},
      submit(){
          this.$refs.uploadForm.validate().then(()=>{
            //校验成功
            alert("成功")
          }).catch((e)=>{
            //失败
            alert("失败:"+e[0].message||'')
          })

      }

		}

}
</script>

<style lang="less" scoped>
  .van-cell--required::before{
    position: absolute;
    left: 0.21333rem;
    color:#ee0a24;
    font-size: 0.37333rem;
    content: '';
  }
</style>

输入框+单选框+复选框+日期控件+下拉框(picker选择器)+级联选择动态渲染

级联截图

具体代码:

    <van-cell-group inset style="font-size:14px;">
                  <!--输入框-->
                  <van-cell v-if="item.type=='input'"  >
                      <van-field colon :required="item.required"  v-model="dataForm[item.infoName]"  :rules="item.required?[{required:`${item.required}`,message:`${item.placeHolder}`}]:[]" 
                        :maxLength="item.maxLength" :label="item.desc" :placeholder="item.placeHolder"/>
                  </van-cell>

                   <!--单选框-->
                   <van-cell v-if="item.type=='radio'"  >
                      <van-field colon   :required="item.required"
                         :rules="item.required?[{required:`${item.required}`,message:`${item.placeHolder}`}]:[]" 
                         :label="item.desc" >
                          <template #input>
                              <van-radio-group v-model="dataForm[item.infoName]" direction="horizontal">
                                  <van-radio :name="itemRadio.value" v-for="itemRadio in item.infoData">{{ itemRadio.name }}</van-radio>
                              </van-radio-group>
                          </template>
                      </van-field>
                  </van-cell>

                   <!--复选框-->
                   <van-cell v-if="item.type=='checkbox'"  >
                      <van-field colon   :required="item.required"  
                         :rules="item.required?[{required:`${item.required}`,message:`${item.placeHolder}`}]:[]" 
                         :label="item.desc" >
                          <template #input>
                              <van-checkbox-group v-model="dataForm[item.infoName]" direction="horizontal">
                                  <van-checkbox :name="checkbox.value" v-for="checkbox in item.infoData">{{ checkbox.name }}</van-checkbox>
                              </van-checkbox-group>
                          </template>
                      </van-field>
                  </van-cell>

                  <!--日期控件  -->
                  <van-cell v-if="item.type=='date'">
                        <van-field  colon :required="item.required"  
                            v-model="dataForm[item.infoName]"  
                            :placeholder="item.placeHolder"
                            :label="item.desc"
                            :rules="[{required:`${item.required}`, message: `${item.placeHolder}`}]" 
                            @click="item.showDate = true" />
                          <van-popup v-model = "item.showDate" round position="bottom">
                              <van-datetime-picker type="date"  @cancel ="item.showDate = false"
                                      @confirm="(date)=> onConfirmDate (date,item)"
                                      v-model="currentDate"
                                      title="选择年月日"
                                      :min-date="item.minDate" :max-date="item.maxDate"/>
                          </van-popup>
                  </van-cell>

                  <!-- 多选框-->
                  <van-cell v-if="item.type=='select'">
                    <!--  v-model="dataForm[item.infoName]" 确认方法的时候已经动态赋值了 -->
                        <van-field
                          :value="item.showOptionName"
                          is-link
                          readonly
                          colon 
                          :required="item.required"  
                          :label="item.desc"
                          :placeholder="item.placeHolder"
                          @click="item.showOption = true"
                        /> 
                        <!-- :ref="item.pickerRef"-->
                        <van-popup  v-model = "item.showOption" round position="bottom">
                          <van-picker
                            value-key="text"
                            show-toolbar
                            :ref="'picker'+index"
                            :class="item.infoName"
                            :title="item.pickerTitle"
                            :columns="item.options"
                            @cancel="item.showOption = false"
                            @confirm="onConfirmSelect"
                            @change ="selectChange"
                          />
                        </van-popup>
                    </van-cell>

                  <!-- 级联选择-->
                  <van-cell v-if="item.type=='cascader'">
                    <van-field
                          :value="item.showOptionName"
                          is-link
                          readonly
                          colon 
                          :required="item.required"  
                          :label="item.desc"
                          :placeholder="item.placeHolder"
                          @click="item.showOption = true"
                        /> 
                        <van-popup  v-model = "item.showOption" round position="bottom">
                          <van-cascader
                           :field-names="fieldNames"
                            :title="item.title"
                            :options="item.options"
                            @close="item.showOption = true"
                            @finish="onFinish"
                          />
                        </van-popup>
                  </van-cell>

                </van-cell-group>


js 省略格式
                   currentDate:new Date(),
                   date:'',
                   showDate:false,
                   fieldNames: {
                    text: 'name',
                    value: 'code',
                    children: 'items',
                  }, 
                  currentFileList:[//测试数据
                   {
                        desc:'姓名',
                        type:'input',
                        infoName:"name",
                        placeHolder:"请输入姓名",
                        required:true,
                        maxLength:'5'
                    }, 
                    {
                        desc:'性别',
                        type:'radio',
                        infoName:"sex",
                        placeHolder:"",
                        required:true,
                        infoData:[{"name":"男","value":"0"},{"name":"女","value":"1"}],
                    }, 
                    {
                        desc:'兴趣',
                        type:'checkbox',
                        infoName:"hobby",
                        placeHolder:"",
                        required:true,
                        infoData:[{"name":"乒乓球","value":"0"},{"name":"游泳","value":"1"},{"name":"爬山","value":"2"}],
                    },
                    {
                        desc:'出生日期',
                        type:'date',
                        infoName:"birthday",
                        placeHolder:"请选择出生日期",
                        required:true,
                        showDate:false,
                        minDate:new Date(1960,0,1),
                        maxDate:new Date()
                    },
                    {
                        desc:'城市',
                        type:'select',
                        infoName:"city",
                        placeHolder:"请选择城市",
                        required:true,
                        options:[
                            { text: '杭州', value: 'Hangzhou' },
                            { text: '宁波', value: 'Ningbo' },
                            { text: '温州', value: 'Wenzhou' },
                            { text: '绍兴', value: 'Shaoxing' },
                            { text: '湖州', value: 'Huzhou' },
                        ],
                        showOption:false,
                        showOptionName:'',
                        pickerTitle:'请选择城市'
                    },
                    {
                        desc:'职业',
                        type:'select',
                        infoName:"job",
                        placeHolder:"请选择职业",
                        required:true,
                        options:[
                            { text: '医生', value: 'doctor' },
                            { text: '教师', value: 'teacher' },
                            { text: '司机', value: 'driver' }
                           ],
                        showOption:false,
                        showOptionName:'',
                        pickerTitle:'请选择职业'
                    },
                    //级联
                    {
                        desc:'地区',
                        type:'cascader',
                        infoName:"area",
                        placeHolder:"请选择地区",
                        required:true,
                        options: [
                                {
                                  name: '浙江省',
                                  code: '330000',
                                  items: [{ 
                                    name: '杭州市', 
                                    code: '330100' ,
                                    items: [{ name: '杭AA区', code: '330101' },{ name: '杭BB区', code: '330102' }]
                                  }],
                                },
                                {
                                  name: '江苏省',
                                  code: '320000',
                                  items: [{ 
                                     name: '南京市',
                                     code: '320100' ,
                                     items: [{ name: '南AA区', code: '320101' },{ name: '南BB区', code: '320102' }]
                                    }
                                  ],
                                },
                        ],
                        showOption:false,
                        showOptionName:'',
                        title:'请选择地区'
                    }]

//方法 省略格式
  confirmDate(date){
        let year = date.getFullYear();
        let month = date.getMonth()+1;
        let day = date.getDate();

        if(month<10){
          month="0"+month;
        }
        if(day<10){
          day="0"+day;
        }
        return `${year}-${month}-${day}`;

      },
      onConfirmDate(date,item){
        item.showDate = false;
        this.date = this.confirmDate(date);//

        if(item.infoData){ //日期是否有规则校验 有校验可以特殊处理

        }
        //表单对象赋值
        this.dataForm[item.infoName]= this.date;

      },
      // 设值方法,change的可以忽略 只是记录下可以直接获得picker实例后这样子使用

       //change设值法  每一次change的时候让picker右边数据变化
    selectChange (picker, values) {
      console.log("picker ",picker);
      console.log("改变的选中值为: ",values.value);
      //picker.$el.className 值是:'van-picker city'  由元素class加空格加指定class
      var infoName = picker.$el.className.substr(11); // 表单使用的正式自定义的动态的class
      this.dataForm[infoName]=values.value;
    },
    //确认设值法 
    onConfirmSelect(value,index){
        console.log("onConfirmSelect--value:",value.text,value.value);
        console.log("onConfirmSelect--index:",index);

        //哪个picker是true 就表示这个值是哪个picker的 可以放进表单中
          for(var i in this.currentFileList){
            var currObj = this.currentFileList[i];
            if(currObj.showOption && currObj.type=='select'){
               this.dataForm[currObj.infoName] = value.value;//表单赋值
               this.currentFileList[i].showOptionName = value.text;//展示值

               this.currentFileList[i].showOption = false;
            }
          }
          console.log("确认后当前表单的值:",JSON.stringify(this.dataForm))
    },
      onFinish( value){
          console.log("级联--value:",value);
          console.log("级联--selectedOptions:",value.selectedOptions);
          console.log("级联--tabIndex:",value.tabIndex);
          var third = value.value;
          var selectedOptions = value.selectedOptions;
          var codeArr = [];
          var nameArr = []
          for (var i in selectedOptions){
            codeArr.push(selectedOptions[i].code);
            nameArr.push(selectedOptions[i].name);
          }
          for(var i in this.currentFileList){
                var currObj = this.currentFileList[i];
                if(currObj.showOption && currObj.type=='cascader'){
                   this.dataForm[currObj.infoName] = third;//表单赋值,这里是只用的最后一级 按需赋值
                   this.currentFileList[i].showOptionName = nameArr.join("/");//展示值
                   this.currentFileList[i].showOption = false;
            }
          }
          console.log("确认后当前表单的值:",JSON.stringify(this.dataForm))

    }

数据库配置

表设计字段:

主键

产品或业务场景代码字段 ,做区别的字段,不同产品不同场景有些字段可能不需要

field_code  字段代码:用于映射到业务表的实体字段上

field_name 字段名称: 用于前端展示label

field_type  字段类型:输入框、单选框、复选框、上传组件类型等等

is_required  字段是否必填

page_no 字段展示的页码,第N页展示哪些字段

display_order 从上至下,字段展示的顺序

field_extend_data  字段扩展数据,里面可存json串,json串可以配置校验或页面想要的一些动态元素,标题什么的

field_extend_data 示例

//前端数组转
var jsonStr = this.dataList[i].fieldExtendData.replace(new RegExp('\"',"gm"),'"');
var arr = eval('('+jsonStr+')');'

前端字段校验规则想动态配数据库的时候:

<van-field colon    :rules="item.required?[{required:`${item.required}`,message:`${item.placeHolder}`}]:[]"> 

<van-field colon    :rules="item.rules?item.rules:[{required:`${item.required}`,message:`${item.placeHolder}`}]"> 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值