vue动态表单DynamicForm

效果:

  

预期:像这样的表单结构,如果在form中一行一行写每个文本域,有点麻烦,封装成一个组件,同类型支持新增和删除

 

  ①DynamicForm.vue

<template>
  <div class="dynamic-form">
    <div class="title">
      <p>{{template.title}}</p>
      <van-icon name="add-o" @click="handleAdd" />
    </div>
    <div class="content" v-for="(item,index) in MyList" :key="index">
      <p class="icon" @click="handleDelete(index)">
        <img src="@/assets/public/delete.svg">
      </p>
      <van-field v-for="(ele,i) in template.labels" :key="i" v-model="item[ele.field]" rows="3" autosize :label="ele.name" placeholder="请输入" type="textarea" maxlength="200"
        show-word-limit clearable required :rules="[{required:true,message:'必填项,不能为空'}]" />
    </div>
  </div>
</template>
<script>
export default {
  model: { prop: 'data', event: 'change' },
  computed: {
    MyList: {
      get: vm => vm.data,
      set(data) {
        this.$emit('change', data)
      }
    }
  },
  props: {
    template: { type: Object, required: true },
    data: { type: Array, require: true }
  },
  methods: {
    handleAdd() {
      this.MyList.push({})
    },
    handleDelete(index) {
      if (this.MyList.length === 1) return this.$toast('必须保留一项')
      this.MyList.splice(index, 1)
    }
  }
}
</script>
<style lang="less" scoped>
.dynamic-form {
  & + & {
    margin-top: 20px;
  }
  .title {
    display: flex;
    justify-content: space-between;
    align-items: center;
    position: relative;
    > p {
      margin-left: 15px;
      font-size: 16px;
      color: #4d5c82;
    }
    .van-icon {
      color: #198cff;
      font-size: 20px;
      font-weight: 600;
    }
    .van-icon::after {
      content: '';
      position: absolute;
      top: -5px;
      bottom: -5px;
      left: -5px;
      right: -5px;
      border-radius: 50%;
    }
    &::before {
      content: '*';
      position: absolute;
      color: #fc5e5e;
    }
  }
  /deep/ .content {
    margin-top: 10px;
    background-color: #f0f4f8;
    border-radius: 5px;
    padding: 15px;
    position: relative;
    > .icon {
      position: absolute;
      right: 15px;
      top: 10px;
      z-index: 10;
    }
    > .icon::after {
      content: '';
      position: absolute;
      top: -5px;
      bottom: -5px;
      left: -5px;
      right: -5px;
      border-radius: 50%;
    }
    .van-cell--required::before {
      color: #fc5e5e;
      left: 0;
    }
    .van-cell::after {
      border-bottom: none;
    }
    .van-cell {
      padding: 0;
      line-height: 1;
      align-items: center;
      margin-top: 20px;
      display: block;
      background-color: #f0f4f8;
      &:first-of-type {
        margin-top: 0;
      }
      .van-field__label {
        margin-left: 15px;
        width: 90%;
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
        word-break: break-all;
        > span {
          font-size: 16px;
          color: #4d5c82;
        }
      }
      .van-field__value {
        margin-top: 10px;
        padding-left: 8px;
        padding-right: 8px;
        line-height: 32px;
        background-color: #fff;
        border-radius: 5px;
        input::-webkit-input-placeholder,
        textarea::-webkit-input-placeholder {
          color: rgba(#4d5c82, 0.6);
        }
        .van-field__control {
          color: #4d5c82;
          font-size: 16px;
        }
        .van-field__word-limit {
          position: absolute;
          right: 5px;
          bottom: 5px;
          color: rgba(#4d5c82, 0.6);
          font-size: 12px;
        }
      }
    }
  }
}
</style>
View Code

 

  ②拜访计划中使用

    // 引入
    import DynamicForm from '@/components/DynamicForm'

    // data
      page2Data: [
        {
          title: '拜访计划',
          variable: 'requirements',
          labels: [
            { name: '初步预测需求点', field: 'requirement' },
            { name: '判断理由', field: 'reason' }
          ],
          data: [{}]
        },
        {
          title: '提问设计(我方提问)',
          variable: 'questions',
          labels: [{ name: '问题', field: 'question' }],
          data: [{}]
        },
        {
          title: '杜宾清单(客户会提的问题或者顾虑)',
          variable: 'duBins',
          labels: [
            { name: '问题', field: 'question' },
            { name: '解决方案', field: 'solution' }
          ],
          data: [{}]
        },
        {
          title: '信任等级',
          variable: 'trustLevels',
          labels: [
            { name: '提升计划', field: 'improvementPlan' },
            { name: '原因', field: 'reason' }
          ],
          data: [{}]
        },
        {
          title: '物料准备',
          variable: 'materials',
          labels: [
            { name: '具体物料', field: 'material' },
            { name: '选择原因', field: 'reason' }
          ],
          data: [{}]
        }
      ]

  DOM:

    <van-form @submit="handleSubmit" validate-trigger='onSubmit'>
      <DynamicForm v-for="(item,index) in page2Data" :key="index" v-model="item.data" :template='item' />
      <div class="page2-footer">
        <van-button native-type="submit" :loading='submitLoading'>提交</van-button>
      </div>
    </van-form>

  得到的数据结构:

      const arr = [
        {
          title: '拜访计划',
          variable: 'requirements',
          labels: [
            { name: '初步预测需求点', field: 'requirement' },
            { name: '判断理由', field: 'reason' }
          ],
          data: [{ requirement: '2', reason: '2' }]
        },
        {
          title: '提问设计(我方提问)',
          variable: 'questions',
          labels: [{ name: '问题', field: 'question' }],
          data: [{ question: '1' }]
        },
        {
          title: '杜宾清单(客户会提的问题或者顾虑)',
          variable: 'duBins',
          labels: [
            { name: '问题', field: 'question' },
            { name: '解决方案', field: 'solution' }
          ],
          data: [{ question: '1', solution: '1' }]
        },
        {
          title: '信任等级',
          variable: 'trustLevels',
          labels: [
            { name: '提升计划', field: 'improvementPlan' },
            { name: '原因', field: 'reason' }
          ],
          data: [{ improvementPlan: '6', reason: '6' }]
        },
        {
          title: '物料准备',
          variable: 'materials',
          labels: [
            { name: '具体物料', field: 'material' },
            { name: '选择原因', field: 'reason' }
          ],
          data: [{ material: '16', reason: '6' }]
        }
      ]
View Code

 

  ③拜访反馈中使用

    // 引入
    import DynamicForm from '@/components/DynamicForm'

    // data
      page2Data: [
        {
          title: '需求调研结果汇总',
          variable: 'requirementList',
          labels: [
            { name: '客户实际需求', field: 'requirement' },
            { name: '判断理由', field: 'reason' }
          ],
          data: [{}]
        },
        {
          title: '客户实际提出的顾虑/问题',
          variable: 'questionList',
          labels: [{ name: '顾虑/问题', field: 'concern' }],
          data: [{}]
        }
      ]

  DOM:

    <van-form @submit="handleSubmit" validate-trigger='onSubmit'>
      <DynamicForm v-for="(item,index) in page2Data" :key="index" v-model="item.data" :template='item' />
      <div class="page2-footer">
        <van-button native-type="submit" :loading='submitLoading'>提交</van-button>
      </div>
    </van-form>

  得到的数据结构:

      const arr = [
        {
          title: '需求调研结果汇总',
          variable: 'requirementList',
          labels: [
            { name: '客户实际需求', field: 'requirement' },
            { name: '判断理由', field: 'reason' }
          ],
          data: [
            { requirement: '1', reason: '2' },
            { requirement: '11', reason: '22' }
          ]
        },
        {
          title: '客户实际提出的顾虑/问题',
          variable: 'questionList',
          labels: [{ name: '顾虑/问题', field: 'concern' }],
          data: [{ concern: '1' }]
        }
      ]
View Code

 

posted @ 2022-03-19 16:53  吴小明-  阅读(3284)  评论(0编辑  收藏  举报