美文网首页
vue动态渲染表单配置项

vue动态渲染表单配置项

作者: 彼得潘北北 | 来源:发表于2020-03-30 16:32 被阅读0次

vue动态渲染表单配置项

在项目中,我们经常会用到各种表单,但是数量一般都不多,那当我们编写大量表单时怎么办呢,难道我们还要一个标签一个标签的写吗?如果各个表单之间又出现了各种级联关系各种判断呢?所以这时候就出现了另外一种方式,我们可以通过对象的方式编写表单项来替换element本来的标签写法,以使我们能够方便清晰的最大化的控制每个表单。

当我们编写一个普通的input表单时,我们一般会直接在template里这样写:

<el-input v-model="inputValue" placeholder="请输入"></el-input>

用了表单配置项后,我们可以这样在data里写:

{
  type: 'input',
  key: 'inputValue',
  label: 'input框:',
  placeholder: '请输入'
}

我们先不讨论怎么就可以这样写了,我们先来明白为什么要这样用

  • 可以通过this.XXX来改变某个表单项
  • 不用再在标签里加各种判断
  • 标签写法太死板
  • render写法,更贴近vue底层

如何配置

input举栗,最后会附上其他的表单项

// 准备一个文件---itemRenders.js
export default {
  name: 'ItemRender',
  props: {
    // 类型,input or select or ...
    type: String,
    // 主要配置项
    config: Object
  },
  // 渲染函数
  render: function (h) {
    switch (this.type) {
      case 'input':
        return inputItem(h, this.config);
      default:
        return '';
    }
  }
};  

function inputItem(h, config) {
  let {
    key, // 绑定的值
    props, // 属性, 如disable等
    listeners, // 事件,如onblur等
    placeholder,
    areaProps // 额外属性如type等
  } = config;
  let on = listeners || {};
  let pps = props || {};
  let area = areaProps || {};
  return h('el-input', {
    props: {
      ...pps,
      value: key,
      disabled: pps.disabled
    },
    attrs: {
      placeholder: placeholder || pps.placeholder || '请输入',
      ...area
    },
    on: {
      ...on,
      // 实现双向绑定
      input: (val) => {
        key = val;
      }
    }
  });
}

如何使用

在.vue文件中使用itemRenders.js

<template>
    <div>
        <item-render
          :type="item.type"
          :config="{
            placeholder: item.placeholder || '',
            ...item.config,
            key: item.key
          }"
        >
        </item-render>
    </div>
</template>

<script>
    import ItemRender from './itemRenders';
    export default {
        components: { 'item-render': ItemRender },
        data() {
            return {
                item: {
                    type: 'input',
                     key: 'inputValue',
                     label: 'input框:',
                     placeholder: '请输入',
                     config: {
                        props: {
                          disabled: true
                        },
                        listeners: {
                          blur: _this.blur1
                        }
                     }
                }
            }
        }
    }
</script>

这只是渲染一个input的写法,但既然会用到这种写法,那就代表要渲染的表单数量可能有点大,像我们项目中有些页面新增时表单项多达100+,所以,如果页面只用到个位数的表单的情况,这里还是建议亲亲直接使用ele提供的标签写法。

渲染大量表单

那渲染大量表单时要怎么配置呢?

其实也很简单,套个form就行了(主要以提交form表单为主)

我们可以先来准备个form表单组件,用的时候只需引入该组件即可

// formRender.vue
<template>
  <el-form
    ref="formRender"
    :model="model"
    :rules="rules"
  >
    <div class="block">
      <el-form-item
        v-for="item in items"
        :key="item.key"
        :label="item.label"
        :prop="item.key"
      >
        <item-render
          :type="item.type"
          :config="{
            placeholder: item.placeholder || '',
            ...item.config,
            model,
            key: item.key
          }"
        >
        </item-render>
      </el-form-item>
    </div>
  </el-form>
</template>
<script>
    import ItemRender from './itemRenders';
    export default {
        components: { 'item-render': ItemRender },
        props: {
            model: {
              type: Object,
              default: () => {}
            },
            // 规则
            rules: {
              type: Object,
              default: () => {}
            },
            items: {
              type: Array,
              default: () => []
            }
        },
    }
</script>

项目中使用

<template>
    <FormRender
        ref="formRender"
        :model="form"
        :rules="basicRules"
        :items="items1"
      ></FormRender>
</template>
<script>
    import FormRender from './formRender';
    export default {
        components: {FormRender},
        data() {
            return {
                form: {
                    formItem1: '',
                    formItem2: [],
                    formItem3: ''
                },
                items1: [
                    // 输入框
                    {
                        type: 'input',
                        key: 'formItem1',
                        label: 'formItem1:',
                        placeholder: '请输入',
                    },
                    // 下拉框
                    {
                        type: 'select',
                        key: 'formItem2',
                        label: 'formItem2:',
                        placeholder: '请选择',
                        config: {
                            props: {
                              filterable: true,
                              clearable: true,
                              disabled: false
                            },
                            options: () => _this.formItem2s,
                            optionConfig: {
                              label: 'name',
                              value: 'code'
                            },
                            listeners: {
                              change: _this.handleChange
                            }
                      }
                    }
                ],
                basicRules: {
                    formItem1: [ { required: true, trigger: 'blur' }]
                },
                formItem2s: []
            }
         }
    }
</script>

其余表单配置项

这里只提供部分常用的给大家做参考,大家也可以从别的角度去考虑,适合我们的并不一定适合所有人

  • 下拉选择框

    function selectItem(h, config) {
    let {
      model,
      key,
      props,
      listeners,
      options,
      optionConfig,
      placeholder,
      syncConfig
    } = config;
    
    let opl = 'label';
    let opv = 'value';
    if (optionConfig) {
      if (optionConfig.label) {
        opl = optionConfig.label;
      }
      if (optionConfig.value) {
        opv = optionConfig.value;
      }
    }
    
    let opts = options();
    let ops = [];
    if (opts) {
      ops = opts.map((option) => {
        return h('el-option', {
          key: option[opv],
          props: {
            label: option[opl] || option['text'],
            value: option[opv],
            disabled: option.disabled
          }
        });
      });
    }
    
    let on = listeners || {};
    let pps = props || {};
    if (syncConfig) {
      pps = {
        ...pps,
        ...syncConfig()
      };
    }
    
    return h(
      'el-select', {
        props: {
          placeholder,
          ...pps,
          value: model[key]
        },
        on: {
          ...on,
          change: (val) => {
            model[key] = val;
            if (on.change) {
              on.change(val);
            }
          }
        }
      },
      ops
    );
    }
    
  • 日期选择器

    function dateItem(h, config) {
      let {
        model,
        key,
        props,
        listeners,
        placeholder,
        type
      } = config;
      let pps = props || {};
      let on = listeners || {};
      return h('el-date-picker', {
        props: {
          ...pps,
          value: model[key]
        },
        attrs: {
          placeholder: placeholder || pps.placeholder || '请输入',
          type: type || 'date'
        },
        on: {
          ...on,
          input: (val) => {
            model[key] = val;
          }
        }
      });
    }
    
  • 计数器

    function inputNumberItem(h, config) {
      let {
        model,
        key,
        props
      } = config;
      let pps = props || {};
      return h('el-input-number', {
        props: {
          ...pps,
          value: model[key]
        },
        on: {
          change: (val) => {
            model[key] = val;
          }
        }
      });
    }
    
  • 上传

    function uploadItem(h, config) {
      let {
        model,
        key,
        props,
        btnProps,
        listeners,
        iconProps
      } = config;
      let pps = props || {};
      let btnProp = btnProps || {};
      let iconProp = iconProps || {};
      let on = listeners || {};
      return h(
        'el-upload', {
          props: {
            ...pps,
            'file-list': model[key]
          },
          class: {
            upload_demo: true
          },
          on: {
            ...on
          }
        },
        [
          h(
            'el-button', {
              props: {
                ...btnProp,
                size: btnProp.size || 'small'
              }
            },
            [
              h('svg-icon', {
                style: iconProp.styles,
                props: {
                  iconClass: iconProp.iconClass
                }
              }),
              '上传'
            ]
          )
        ]
      );
    }
    
  • 级联选择器

    function cascaderItem(h, config) {
      let {
        model,
        key,
        props,
        listeners,
        options,
        optionProps
      } = config;
      let ops = options();
      let on = listeners || {};
      let pps = props || {};
      return h('el-cascader', {
        props: {
          value: model[key],
          ...pps,
          options: ops,
          props: optionProps
        },
        on: {
          change: (val) => {
            model[key] = val;
            if (on.change) {
              on.change(val);
            }
          }
        }
      });
    }
    
  • 时间选择器

    function timePicker(h, config) {
      let {
        model,
        key,
        props,
        listeners,
        placeholder,
        type,
        syncConfig
      } = config;
      let pps = props || {};
      if (syncConfig) {
        pps = {
          ...pps,
          ...syncConfig()
        };
      }
      let on = listeners || {};
      return h('el-time-picker', {
        props: {
          ...pps,
          value: model[key]
        },
        attrs: {
          placeholder: placeholder || pps.placeholder || '请输入',
          type: type || 'date'
        },
        on: {
          ...on,
          input: (val) => {
            model[key] = val;
          }
        }
      });
    }
    

相关文章

网友评论

      本文标题:vue动态渲染表单配置项

      本文链接:https://www.haomeiwen.com/subject/qwvvuhtx.html