需求:怎样快速的生成表单,不用每次都去拷贝粘贴
思路:用过antd或者iView框架的都知道,参考table组件,给出一个Column和dataSource通过遍历循环的方式去生成表格,同样是否也可以给出一个2个参数去生成一个表单呢?答案显而易见是可行的,于是我写了一个FormMain的组件用来快捷是生成表单


代码如下

// FormMain.vue
<script type="text/jsx">
function noop() {}
let id = 0
export default {
  name: 'FnFormMain',
  props: {
    asyncProps: Object,
    data: {
      type: Object,
      default: () => { return {} }
    },
    config: {
      type: Array,
      default: () => {
        return []
      }
    }
  },
  data() {
    return {
      dictionaryData: {
      },
      propsAttar: {}
    }
  },
  computed: {
  },
  created() {
    let arr = ['select', 'radio', 'checkbox']
    this.config.map(el => {
      let isArray = Array.isArray(el)
      if (isArray) {
        el.map(l => {
          if (arr.indexOf(l.type) >= 0) {
            this.setProps(l)
          }
        })
      } else if (arr.indexOf(el.type) >= 0) {
        this.setProps(el)
      }
    })
  },
  methods: {
    remoteMethod() {
      debugger
    },
    handleAvatarSuccess(url, file, key) {
      this.data[key] = url
      this.onUploadSuccess(url, file)
    },
    beforeUploadFile(file) {
      this.beforeUpload(file)
    },
    setProps(el) {
      let { async, key, data = [] } = el
      if (async) {
        this.$set(this.propsAttar, key, [])
        async(key).then(res => {
          el.data = this.propsAttar[key] = res
        })
      } else {
        el.data = this.propsAttar[key] = typeof data === 'string' ? this.dictionaryData[data] : data
      }
    },
    formatHtml(el, key, createElement) {
      let relust
      let { disabled } = el

      let isDisabled = disabled ? disabled.value === undefined ? !!this.data[disabled.key] : this.data[disabled.key] === disabled.value : false

      switch (el.type) {
        case 'select':
          if (el.data || this.propsAttar[key]) {
            if (!el.data) {
              relust = ''
              return
            }
            relust = (
              <el-select disabled={isDisabled} multiple={el.multiple} allow-create={el.allowCreate} default-first-option remote={el.remote} remote-method={(value) => {
                el.remoteMethod(value, el)
              }} clearable filterable={el.filterable} v-model={this.data[key]} placeholder={`请选择${el.label}`}>
                {
                  el.group
                    ? el.data.map(e =>
                      <el-option-group label={e.label} key={e.value}>
                        {
                          e.children.map(subEl => <el-option label={subEl.label} value={subEl.value}> </el-option>)
                        }
                      </el-option-group>
                    )
                    : el.data.map(subEl => <el-option label={subEl.label} value={subEl.value}></el-option>)
                }
              </el-select>
            )
          } else {
            relust = '字段数据不存在'
          }
          break
        case 'input':
          relust = (
            <el-input placeholder={`请输入${el.label}`} v-model={this.data[key]}></el-input>
          )
          break
        default:
          break
      }
      return relust
    }
  },
  render(createElement) {
    const component = (
      <div>
        {
          this.config.map(el => {
            let isArray = Array.isArray(el)
            let { key, labelWidth, label, show } = isArray ? el[0] : el
            let relust = ''
            if (isArray && (el[0] && el[0].col)) {
              relust = []
              el.forEach((item, index) => {
                let { key, labelWidth, label, show } = item
                relust.push(
                  <el-col span={12}>
                    <el-form-item v-show={show ? (this.data[show.key] === show.value) : true} label-width={labelWidth} prop={key} label={ labelWidth === undefined || labelWidth !== '0' ? label : '' }>
                      {
                        this.formatHtml(item, item.key, createElement)
                      }
                    </el-form-item>
                  </el-col>
                )
              })

              return (
                <el-row gutter={10}>
                  {relust}
                </el-row>
              )
            } else if (isArray) {
              relust = []
              let len = el.length
              el.forEach((item, index) => {
                relust.push(
                  <el-col span={11}>
                    {
                      this.formatHtml(item, item.key, createElement)
                    }
                  </el-col>
                )
                if (index < len - 1) {
                  relust.push(
                    <el-col class="text-center" span={2}> - </el-col>
                  )
                }
              })
            } else {
              relust = this.formatHtml(el, key, createElement)
            }
            return (
              <el-form-item v-show={show ? Array.isArray(show) ? show.reduce((a, b) => { return a && this.data[b.key] === b.value }, true) : (this.data[show.key] === show.value) : true} label-width={labelWidth} prop={key} label={ labelWidth === undefined || labelWidth !== '0' ? label : '' }>
                {relust}
              </el-form-item>
            )
          })
        }
      </div>
    )
    return component
  },
  watch: {
  }
}

</script>
// template
<div id="app">
    <el-form ref="form" :model="data" style="width: 460px;" label-width="80px">
        <FormMain :config="config" :data="data"></FormMain>
    </el-form>
</div>
import FormMain from "./components/FormMain";

export default {
    name: "App",
    components: { FormMain },
    data() {
        return {
            config: [
            { label: "A", type: "input", key: "a", labelWidth: "80px" },
            {
                label: "BB", type: "radio",
                key: "d",
                data: [ { label: "x", value: 1 },
                    { label: "y", value: 2 },
                    { label: "z", value: 3 }
                ]
            },
            { 
                label: "B",
                type: "select",
                key: "b",
                async: this.asyncData
            },
            { label: "C", tip: "这是C", type: "input", key: "c" },
            [

                {

                label: "日期范围",

                type: "date",

                key: "beginDate",

                tip: "结束时间没有填写则以最近天数为准,填写结束时间则最近天数失效"

                },

                { label: "结束日期", type: "date", key: "endDate" }
            ]
            ],
            data: {
                a: 1,
                b: 2,
                c: 3,
                d: 1,
                beginDate: new Date(),
                endDate: new Date()
            }
        };
    },
    methods: {
        asyncData() {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve([
                        { label: "A", value: 1 },
                        { label: "B", value: 2 },
                        { label: "C", value: 3 }
                    ]);
                }, 1000);
            });
        }
    }
};

支持:

  • select radio,checkbox异步请求数据
  • label提示信息
  • 一列多个输入框
  • 指定label宽度

可以点击查看实例 demo链接

image.png


2ming
162 声望1 粉丝

前端实践以及资料整理 [链接]