npm.io
0.1.0 • Published 5 years ago

@lazyb/l-form

Licence
MIT
Version
0.1.0
Deps
1
Size
1.5 MB
Vulns
0
Weekly
0

LForm js 对象 配置表单

介绍

基于 Vue 2.X、Element-ui 2.X 的使用 js 对象 进行配置生成的表单,懒人专用表单 —— LazyForm

该表单的特点如下:

  1. 支持表单联动
  2. 支持任意类型的输入项,只要该输入项实现了 v-model
  3. 支持动态更新表单配置项
  4. 支持灵活配置表单项布局

作者本人使用 LForm 的原因:

  1. 提供表单项的联动,只需简单配置就能实现
  2. 配置直接生成表单,不用写一堆臃肿的模板
  3. 配置支持设置默认属性,使得能够统一表单项的默认设置
  4. 支持配置校验规则,不用写一堆 if else 来手动校验
  5. 数据驱动视图,只需要修改配置对象,则会自动刷新UI
  6. 支持在指定位置渲染 slot
  7. 通过 v-model 直接拿到/设置 表单的值
  8. 支持自定义表单项的布局
  9. ...

以下均假设已经全局安装了 Element-ui
配置项中,除了 LForm 特有的配置外,其他未做说明的配置项均为对应 'element' 组件的配置

使用

安装
NPM
npm i --save @lazyb/l-form
YARN
yarn add @lazyb/l-form
简单场景

在最简单的情况下,无需其他配置就可以使用

// main.js
import LForm from '@lazyb/l-form';

Vue.use(LForm);
<l-form :config="config" label-width="100px" @submit="submit"></l-form>
// 由于没有做其他配置,所以需要指明表单使用的组件 component  
// 其中 slot 是特殊的,代表这里需要渲染一个 具名slot, slot 名是配置项中的 key  
export default {
  name: 'SimpleDemo',

  data() {
    return {
      config: {
        formItems: [
          { component: 'el-input', label: '活动名称', key: 'name' },
          { component: 'el-switch', label: '即时配送', key: 'delivery' },
          { component: 'el-input', label: '备注', key: 'desc' },
        ],
      },
    };
  },

  methods: {
    // ts 类型注释
    submit(form: object) {
      this.$message.info(`提交:${JSON.stringify(form)}`);
    },
  },
};
简单场景 - 带表单校验
  <l-form :config="config" label-width="100px" @submit="submit"></l-form>
export default {
  name: 'RulesDemo',

  data() {
    return {
      config: {
        formItems: [
          {
            component: 'el-input',
            label: '活动名称',
            key: 'name',
            rules: [{ required: true, message: '活动名称不能为空', trigger: 'change' }],
          },
          { component: 'el-switch', label: '即时配送', key: 'delivery' },
          { component: 'el-input', label: '备注', key: 'desc' },
        ],
      },
    };
  },

  methods: {
    submit(form: object) {
      this.$message.info(`提交:${JSON.stringify(form)}`);
    },
  },
};
简单场景 - 自定义布局
  <l-form :config="config" label-width="100px" @submit="submit"></l-form>
export default Vue.extend({
  name: 'UiDemo',

  data() {
    return {
      config: {
        formItems: [
          {
            component: 'el-input',
            label: '活动名称',
            key: 'name',
            rules: [{ required: true, message: '活动名称不能为空', trigger: 'change' }],
          },
          {
            component: 'el-input',
            label: '活动名称2',
            key: 'name2',
            rules: [{ required: true, message: '活动名称不能为空', trigger: 'change' }],
          },
          { component: 'el-switch', label: '即时配送', key: 'delivery' },
          { component: 'el-switch', label: '即时配送2', key: 'delivery2' },
          { component: 'el-input', label: '备注', key: 'desc' },
        ],
        ui: [
          { name: 12, name2: 12 },
          { delivery: 12, delivery2: 12 },
        ],
      },
    };
  },

  methods: {
    submit(form: object) {
      this.$message.info(`提交:${JSON.stringify(form)}`);
    },
  },
});
简单场景 - 带表单联动
  <l-form :config="config" label-width="100px" @submit="submit"></l-form>
export default Vue.extend({
  name: 'LinkDemo',

  data() {
    return {
      config: {
        formItems: [
          {
            component: 'el-input',
            label: '活动名称',
            key: 'name',
            rules: [{ required: true, message: '活动名称不能为空', trigger: 'change' }],
          },
          { component: 'el-switch', label: '即时配送', key: 'delivery' },
          {
            component: 'el-input',
            label: '配送要求',
            key: 'info',
            ifRender(form: any) {
              return form.delivery;
            },
            rules: [{ required: true, message: '配送要求不能为空', trigger: 'change' }],
          },
          { component: 'el-input', label: '备注', key: 'desc' },
        ],
      },
    };
  },

  methods: {
    submit(form: object) {
      this.$message.info(`提交:${JSON.stringify(form)}`);
    },
  },
});
简单场景 - 插槽
  <l-form :config="config" label-width="100px" @submit="submit">
    <h3 slot="slot-name">我是自定义的表单项</h3>
    <h3 slot="slotField-name">我是表单项的自定义输入元素</h3>
    <h3>我是默认插槽</h3>
    <h3 slot="footer">我是自定义提交按钮</h3>
  </l-form>
export default Vue.extend({
  name: 'SlotDemo',

  data() {
    return {
      config: {
        form: {
          submitText: ['确定以及肯定', '狠心放弃'],
        },
        formItems: [
          {
            component: 'el-input',
            label: '活动名称',
            key: 'name',
            rules: [{ required: true, message: '活动名称不能为空', trigger: 'change' }],
          },
          { component: 'slot', key: 'slot-name' },
          { component: 'el-switch', label: '即时配送', key: 'delivery' },
          { component: 'slotField', label: '一个自定义输入元素的表单项', key: 'slotField-name' },
          {
            component: 'el-input',
            label: '配送要求',
            key: 'info',
            ifRender(form: any) {
              return form.delivery;
            },
            rules: [{ required: true, message: '配送要求不能为空', trigger: 'change' }],
          },
          { component: 'el-input', label: '备注', key: 'desc' },
        ],
      },
    };
  },

  methods: {
    submit(form: object) {
      this.$message.info(`提交:${JSON.stringify(form)}`);
    },
  },
});

API

Props
参数 说明 类型 默认值
v-model (value) 当前表单的值 object -
config 当前表单的配置参数 object -
[otherFormProps: string] el-form 的其他配置参数 any -

表单赋值采用的合并操作,并不是替换操作,类似 Object.assign ,所以不会删除 val 中没有的键名的值
例如表单值为: { a: 2, b: 1 }, val 值为 { a: 1 },则赋值后的结果为 { a: 1, b: 1 }
如果需要清空值,请使用 reset()

config
参数 说明 类型 默认值
formItems 表单项的配置参数 itemConfig[] -
ui 表单项的布局配置参数 layoutConfig[] -
form 表单的配置参数 config -
formItems
参数 说明 类型 默认值
type 表单项的类型,需要在 typeMap 中指明组件名称 string -
key 当前表单项绑定的属性名/slot的具名名称 string -
modifiers v-mode 的修饰符,支持 trim 和 number [string] -
on 当前表单项绑定的事件(需要自行处理 this 指向) object: {event} -
nativeOn .native 绑定的事件(需要自行处理 this 指向) object: {event} -
component 表单项的标签名/表单项(直接引入),优先级高于 type VNode | string 'div'
label 表单项展示的 label 名 string -
[jsxPropName] 其他支持 jsx 的一些属性 any -
props 表单项的配置参数,直接透传给对应表单项,也可以写成方法动态获取 object | function -
ifRender 表单项的是否渲染计算方法,根据计算出的结果决定是否渲染表单项,表单联动的实现机制 function -
[formItemProp] 其他表单label需要的配置,可以理解为 el-form-item 需要的配置 any -

component 有两个特殊的值: slot 和 slotField。其中 slot 为完全使用 slot 生成表单项(需要自行实现 el-form-item),而 slotField 则仅使用 slot 生成输入组件

props 为当前表单项的实际输入组件的配置。例如:{ component: 'el-input' },此时的 props 应该为 el-input 的配置

props 是个函数时:props(form: form的当前值, config: 表单项当时的配置值, context: 当前组件的父组件实例)

ifRender(form: form的当前值, config: 表单项当时的配置值, context: 当前组件的父组件实例)

props 取值顺序是:typeMap.props -> item.props
后面对象的同名属性会覆盖前面的对象的同名属性,使用的 Object.assign 实现

type 为 slot / slotField 类型的表单项,其实是一个 slot 占位,slot 名与 key 或者 slot 属性的值相同

ui

布局使用 el-row 和 el-col 实现,也就是说行列的配置项分别对应 el-row 和 el-col 的配置。
特别的,当列配置,也就是说 key 的属性值为数字时,表明只配置列的 span 。例如: { name: 12 } 等价于 { name: { span: 12 } }
如果对应的 key 没有配置 ui 则表明该表单项单独占一行且铺满当前行

参数 说明 类型 默认值
[formKey: string] 以表单key作为标识,配置对应的布局数据,可以是数字或者一个对象 number | object -
$$row 配置当前行的属性,也就是配置 el-row 的属性 object -
form
参数 说明 类型 默认值
submitText [确定按钮文本,取消按钮文本] 用于自定义按钮文描,如果是更复杂的场景,请使用 footer 具名 slot Array ['确定', '取消']
[ElFormPropName: string] el-form 的配置项 any -

form 可以在配置参数中配置,也可以直接配置在 LForm 组件上,写在配置参数里面的好处是可以 cv 复用

slots
参数 说明 类型 默认值
default 默认 slot 在表单项下方,提交按钮上方,用于展示一些提交提示文描 _ -
footer 表单提交按钮区域的具名slot,用于自定义提交按钮 _ -
[itemSlotName: string] slot 表单项,用来自定义表单输入组件 _ -

表单项 slot 有 slot 和 slotField 之分,需要注意

Events

LForm 使用 v-model 进行值管理,所以会冒泡 input 事件
其他表单项事件由各个表单项确定,监听事件需要自行定义在配置项中

事件 说明 回调参数
input 表单内容变化时触发 value: object (当前表单的值,不包含 ifRender 隐藏的项的值)
confirm 用户点击确认按钮触发 value: object (原始表单的值,包含 ifRender 隐藏的项的值)
submit 用户点击确认按钮且表单校验通过触发 value: object (当前表单的值,不包含 ifRender 隐藏的项的值)

一般情况,都只需要去除了 ifRender 隐藏项的表单值,所以 v-model 和 submit 都冒泡的该值
如果需要原始表单值,可以在 confirm 事件中拿到,或者通过 slot 直接拿 LForm 的 form 属性的值

方法

通过 ref 可以获取到 Form 实例并调用实例方法

方法名 说明 参数 返回值
reset 重置表单值为指定的值 val: Object -
refreshUI 强制重新计算配置项,进行UI刷新 force: boolean (true:无论是否有更新,强制刷新) -

一般情况下赋值只需要修改 v-model 绑定的值即可,除非需要修改隐藏项的值,才需要使用 reset
理论上你永远都不需要使用 refreshUI 方法,如果你遇到了需要使用的场景,请联系我

Q&A

  1. Q:为什么使用 v-model 来实现数据绑定?A:符合 vue 使用者的习惯,而且可以做到和表单项解耦。
  2. Q:表单项的值是复杂对象怎么办?A:其他和单值没区别。
  3. Q:如果没有使用 Element-ui 怎么办?A:可以只引入 el-form/el-form-item/el-row/el-col 四个组件,其他输入项使用其他组件库。但是还是建议使用 Element-ui,或者 fork 一份代码自行实现其他组件库的表单组件...
  4. ...

TODO

后面计划要做的事情:

  1. 支持安装的时候配置默认的 form 配置、默认的 row 配置
  2. 补充 typeMap 部分的文档、示例以及单元测试
  3. ...

Keywords