Vue2 Element Schema Form 配置式生成表单的实现

目录
  • 前置知识点
    • Component
    • $attrs
    • $listeners
  • 表单的结构是什么样的
  • 配置数组数据结构
  • 结语

前置知识点

为了实现一个Schema Form配置式表单的生成,需要了解一部分前置知识点。

Component

vue 提供了一个内置组件 Component,用来动态渲染组件,举个例子,本篇文章以Element UI 为例,假设我们全局注册了Element UI的组件,那么下面一段代码

<Component is="el-input"></Component>

将被渲染为el-input组件。

好了,最重要的实现知识点已经完了,只要了解了这一点,我这个Schema Form的实现思路,你就能完全看懂了,就这么简单。

但是为了我们表单的易用性,我们再了解一点儿其他的。

比如Component组件并非只能接收一个字符串,渲染全局组件,同时可以接收一个Component组件,也就是说,当我们Element UI 组件没有全局注册的时候,我们可以通过import { ElInput } from 'element',传递给Component组件,同样可以完成渲染一个el-input组件的功能。

$attrs

第二个知识点,vue属性透传,假如你有这么一个疑惑 —— 我对el-input进行了二次封装,那el-input接收的props我是否需要在二次封装的组件中进行props的定义,再逐一传递给el-input才能生效。

如果有这样的疑惑那么$attrs可以帮你,对于二次封装的组件,通过定义v-bind="$attrs",传递给父组件的属性即可透传给el-input,于是就有了这么一个疑问,$attrs可以绑定给v-bind,那么一个普通的对象可以吗,答案是可以的。

这是我们 schema form 变得好用的第二个重要的知识点。

$listeners

$attrs 相同,做事件透传的,通过v-on绑定。

以上就是我认为,实现Schema Form配置式生成表单所需要掌握的全部知识及扩展思考,接下来,我们简单完成一个配置式表单.

表单的结构是什么样的

1、我可能希望对表单进行一部分特殊的处理,所以,包一层div总是没错的,当然,这是我的习惯,你们可以自行选择。

2、既然是表单,那一定被el-form包裹。

3、为了配置式布局的需要,我希望引入el-row el-col栅格系统

4、无论如何完善表单,必然不可能满足所有要求,那最简单的方式就是抛出slot

5、有些时候我希望渲染文本呢?有些时候我希望渲染字段的值而不涉及任何组件呢?

6、最后才是渲染对应的组件

那么,一个表单的结构化雏形就完成了。

<div class="schema-form">
    <el-form>
        <el-row>
            <el-col v-for="item in config" :key="item.key">
                <el-form-item>
                    <slot v-if="item.component === 'slot'" :name="item.slotName"></slot>
                    <div v-else-if="item.component === 'innerText'"></div>
                    <template v-else>
                        渲染对应组件,但需要对某些组件特殊处理
                    </template>
                </el-form-item>
            </el-col>
        </el-row>
    </el-form>
</div>

从上面的结构中,我们再来思考,我们的配置config数组的字段结构应该是什么样的。

配置数组数据结构

1、el-form 可能需要一些字段注入,作为最外层的组件,将传入schema form的字段都给它

2、el-form 需要传入一个数据源,这个数据源可以内部定义再传给外部,也可以传入一个对象,利用对象的特性做双向绑定,我选择了后者

3、el-col项可能有时不显示,所以config上扩展一个字段hidden,用于控制该项是否显示。

4、el-form-item的属性透传

5、innerText的样式定义

一些特殊的描述出来了,其余的再赘述,那么,config的数据结构就是这样

{
    key: '', // 当前字段的 key 值,同时会传到 el-form-item 的prop,不传数据验证和重置会失效
    label: '', // 当前 el-form-item 的label
    hidden: '', // 当前表单项是否展示
    labelWidth: '', // el-form-item 的label宽度
    component: '', // 支持 slot、innerText、Component,渲染成什么
    slotName: '', // compoment 为 slot 时,该值为对应slot的名字供外部使用
    innerClass: '', // component 为 innerText 时,给文本的样式,通常为全局样式
    innerStyle: '', // 同上
    innerText: '', // component 为 innerText 时,优先显示的文本,否则会显示当前的字段值
    itemProps: '', // 注入到 el-form-item 的属性
    props: '', // 当 component 为渲染组件时,注入到渲染组件当中的属性
    listeners: '', // 当 component 为渲染组件时,注入到渲染组件当中的事件
}

当把这些实现之后,其余需要扩展的功能可以自行实现,我这里也只是在业务中的扩展,并非完善的。

于是,我们的表单组件就变成了这样

<template>
  <div class="nx-form">
    <el-form
      ref="form"
      v-bind="$attrs"
      :model="source"
      class="nx-form"
    >
      <el-row :gutter="20">
        <el-col
          v-for="item in config"
          :key="item.key"
          :span="item.hidden ? 0 : item.span || 8"
        >
          <el-form-item
            v-if="!item.hidden"
            :label="item.label"
            :prop="item.key"
            :label-width="item.labelWidth || labelWidth || '120px'"
            v-bind="item.itemProps"
          >
            <slot v-if="item.component === 'slot'" :name="item.slotName"></slot>
            <div
              v-else-if="item.component === 'innerText'"
              :class="item.innerClass"
              :style="item.style"
            >
              {{ item.innerText || source[item.key] }}
            </div>
            <template v-else>
              <div class="nx-flex-align-center">
                <component
                  :is="item.component"
                  v-model="source[item.key]"
                  style="width: 100%;flex: 1;"
                  v-bind="item.props"
                  v-on="item.listeners"
                >
                  <template v-if="item.component === 'el-radio-group'">
                    <el-radio
                      v-for="(radio, radioIndex) in item.data"
                      :key="radioIndex"
                      style="margin-top: 10px;"
                      :label="radio.value"
                      :disabled="radio.disabled"
                    >
                      {{ radio.label }}
                    </el-radio>
                  </template>

                  <template v-if="item.component === 'el-checkbox-group'">
                    <el-checkbox
                      v-for="(checkbox, checkboxIndex) in item.data"
                      :key="checkboxIndex"
                      :label="checkbox.value"
                    >
                      {{ checkbox.label }}
                    </el-checkbox>
                  </template>

                  <template v-if="item.component === 'el-select'">
                    <el-option
                      v-for="(option, optionIndex) in item.data"
                      :key="optionIndex"
                      :label="option.label"
                      :value="option.value"
                    ></el-option>
                  </template>
                </component>
                <div
                  v-if="item.after"
                  class="nx-form__after"
                >
                  {{ item.after }}
                </div>
              </div>
              <div
                v-if="item.tips"
                class="nx-form__tips"
                v-html="item.tips"
              ></div>
            </template>

          </el-form-item>
          <!-- <div
            v-if="item.tips"
            :style="{ marginLeft: item.labelWidth || '120px' }"
            class="nx-form__tips"
            v-html="item.tips"
          ></div> -->
        </el-col>
      </el-row>
    </el-form>
  </div>
</template>
export default {
  name: 'NxForm',
  components: {},
  props: {
    config: {
      type: Array,
      default: () => []
    },
    source: {
      type: Object,
      default: () => ({})
    }
  },
  methods: {
    resetFields() {
      this.$refs.form.resetFields();
    },
    clearValidate() {
      this.$refs.form.clearValidate();
    },
    async validate() {
      const valid = await this.$refs.form.validate();
      return valid;
    }
  }
};

可以看到,我扩展了一个data字段,用来作为el-select el-checkbox-group el-radio-group的数据源,这些特殊的组件单独列出就行了,基本上也之后有这么几个。

methods里也只是为了方便添加了一些常用的form方法,基本不做逻辑处理。

现在看一下,这样的配置可以生成怎样的表单

注意:我这里定义了一部分全局样式,比如在schema form下的组件,全部占满整格,使其比较美观。

生成这样一个常用的筛选项表单

<template>
  <div>
    <nx-form
      ref="searchForm"
      :source="searchForm"
      :config="searchConfig"
    >
      <div slot="search">
        <el-button type="primary" @click="$refs.nxTable.search(1)">查询</el-button>
        <el-button @click="reset()">重置</el-button>
      </div>
    </nx-form>
  </div>
</template>
<script>
export default {
  data() {
     searchForm: {
        keyWord: '',
        newsType: '',
        newsStatus: '',
        publishTime: [],
        createTime: []
     },
  },
  computed: {
      searchConfig() {
      return [
        {
          key: 'keyWord',
          component: 'el-input',
          span: 8,
          label: '关键字',
          props: {
            placeholder: '标题/创建人',
            clearable: true
          }
        },
        {
          key: 'newsType',
          component: 'el-select',
          span: 8,
          label: '类型:',
          props: {
            placeholder: '请选择',
            clearable: true
          },
          data: this.newsTypes
        },
        {
          key: 'newsStatus',
          component: 'el-select',
          span: 8,
          label: '状态:',
          props: {
            placeholder: '请选择',
            clearable: true
          },
          data: statusTypes
        },
        {
          key: 'publishTime',
          component: 'el-date-picker',
          label: '发布时间:',
          span: 8,
          props: {
            clearable: true,
            valueFormat: 'timestamp',
            type: 'datetimerange',
            defaultTime: ['00:00:00', '23:59:59'],
            rangeSeparator: '-',
            startPlaceholder: '请选择开始时间',
            endPlaceholder: '请选择结束时间'
          }
        },
        {
          key: 'createTime',
          component: 'el-date-picker',
          label: '创建时间:',
          span: 8,
          props: {
            clearable: true,
            valueFormat: 'timestamp',
            type: 'datetimerange',
            defaultTime: ['00:00:00', '23:59:59'],
            rangeSeparator: '-',
            startPlaceholder: '请选择开始时间',
            endPlaceholder: '请选择结束时间'
          }
        },
        {
          component: 'slot',
          slotName: 'search',
          span: 8,
          labelWidth: '0'
        }
      ];
    }
  }
}
</script>

其余的找了一些,也没啥特别的,就不贴了,简单来说,这个百来行的组件,应用在多个大型项目当中,易用性,扩展性,没有出现什么问题,配合我们自定义的其他table组件、dialog组件,十分钟就可以实现一个完整的B端增删改查。

值得一提的是,为了表单的易用性,我们基本上所有的自定义组件都支持了使用v-model做数据绑定,达到简单易用的效果。

结语

代码是找了一个很久的项目写的一个思路,之后的项目中都有改进优化,大致只是分享一个思路,如果有什么想法的,欢迎指正。

到此这篇关于Vue2 Element Schema Form 配置式生成表单的实现的文章就介绍到这了,更多相关Vue2 Element Schema Form生成表单内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅谈XML Schema中的elementFormDefault属性

    elementFormDefault属性与命名空间相关,其值可设置为qualified或unqualified 如果设置为qualified: 在XML文档中使用局部元素时,必须使用限定短名作为前缀 sean.xsd: <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:sean=&

  • Vue2 Element Schema Form 配置式生成表单的实现

    目录 前置知识点 Component $attrs $listeners 表单的结构是什么样的 配置数组数据结构 结语 前置知识点 为了实现一个Schema Form配置式表单的生成,需要了解一部分前置知识点. Component vue 提供了一个内置组件 Component,用来动态渲染组件,举个例子,本篇文章以Element UI 为例,假设我们全局注册了Element UI的组件,那么下面一段代码 <Component is="el-input"></Comp

  • 基于react hooks,zarm组件库配置开发h5表单页面的实例代码

    最近使用React Hooks结合zarm组件库,基于js对象配置方式开发了大量的h5表单页面.大家都知道h5表单功能无非就是表单数据的收集,验证,提交,回显编辑,通常排列方式也是自上向下一行一列的方式显示 , 所以一开始就考虑封装一个配置化的页面生成方案,目前已经有多个项目基于此方式配置开发上线,思路和实现分享一下. 使用场景 任意包含表单的h5页面(使用zarm库,或自行适配自己的库) 目标 代码实现简单和简洁 基于配置 新手上手快,无学习成本 老手易扩展和维护 写之前参考了市面上的一些方案

  • jQuery validate+artdialog+jquery form实现弹出表单思路详解

    功能描述: 在页面弹出一个form表单,ajax无刷新提交表单,表单需通过验证. 适用范围: 适用于在列表页面新增,修改记录. 需要加载的js文件: jquery.min.js artDialog.js iframeTools.js jquery.form.js jquery.validate.js 实现思路: 在页面中将表单放到一个隐藏的容器中,用artdialog弹出该form并对form加上jqueryvalidate验证,提交采用jqueryform ajax提交,由于都是用现成的插件写

  • Smarty简单生成表单元素的方法示例

    本文实例讲述了Smarty简单生成表单元素的方法.分享给大家供大家参考,具体如下: smarty生成表单元素功能实现的原理是:给smarty一个数组,用于生成和显示菜单或选项,另外在传递一个选项的值,用于默认选择的匹配: 示例如下: php文件:index.php <?php include("smarty_inc.php"); $smarty->assign('cust_ids',array(1000,1001,1002,1003)); $smarty->assig

  • jquery.form.js异步提交表单详解

    本文实例为大家分享了jquery.form.js异步提交表单的具体代码,供大家参考,具体内容如下 引入脚本: <script type="text/javascript" src="/js/jquery.form.min.js"></script> <script src="/js/json2.js"></script> //前端代码: <form id="f1">

  • JSP实现用于自动生成表单标签html代码的自定义表单标签

    本文实例讲述了JSP实现用于自动生成表单标签html代码的自定义表单标签.分享给大家供大家参考.具体如下: 这个是自己写的一个简单的JSP表单标签,用于自动生成checkbox,select,radio等标签,传入菜单集合生成html代码,自动选中指定值,用于java web项目的jsp页面. 1. Servlet部分代码: Map<String, String> map = new HashMap<String, String>(); map.put("2",

  • vue中项目如何提交form格式数据的表单

    目录 vue提交form格式数据的表单 先将数据处理 数据上传 封装文件 vue form表单最简写法 vue提交form格式数据的表单 先将数据处理 let formData = new FormData(); for(let key in this.telForm){      formData.append(key,this.telForm[key]); } 数据上传 //采用封装的post方法上传 this.postRequest('web/login/mobile',formData)

  • 前端vue2 element ui高效配置化省时又省力

    目录 前言 一.场景介绍 1. 业务场景 2. 配置化想法萌生 二.设计 & 实现 1. 设计协议 2. 实现渲染器 3. render函数 & 配置数据 4.丰富组件能力,实现业务 三.配置静态化 前言 这篇文章是笔者曾经全盘负责了接近一年的广告投放系统沉淀下来的开发经验,大家各取所需,不喜勿喷-当然啦,有自己的见解.更好的建议的大牛朋友们,我们评论区见-hhh,大多提点高见,让笔者继续学习继续进步! 本文从 场景介绍 . 设计&实现 . 性能优化 三个部分进行讲解.笔者当时的技

  • jpa多数据源时Hibernate配置自动生成表不生效的解决

    目录 application.yml如下 下面是DataSource的配置 下面是第一个数据源的配置 下面是第二个数据源的配置 jpa配置多数据源教程很多,在Springboot2之后有一些变化,来看一下. application.yml如下 spring: application: name: t3cc datasource: primary: jdbc-url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/${DB_NAME

  • element基于el-form智能的FormSmart表单组件

    目录 目的 源码 关键文档,大部分复制el-form Attributes Methods Events Slot Scoped Slot Form-Item Attributes Row Attributes Col Attributes 基本用法 使用场景 1. 通用列表搜索条件 2.弹窗写法优化 目的 el-form 表单配置化,后期可以利用后端进行配置表单 支持栅格布局 el-form 属性大部分都支持 公共配置可以统一处理,如trim.input宽度等 最基本的组件,利用这组件后期可以

随机推荐