# 使用文档

## 组件参数

|  属性名   | 说明  | 类型 |  可选值 |  默认 |
|  ----  | ----  | ----  | ----  | ----  |
|  v-model/value  | 双向绑定的表单对象，表单项的输入会反映到该对象同名的字段上  | Object  | -  | - |
|  fields  | 定义字段及相关属性，详细参考下表  | Array  | -  | - |
|  formConfig  | 表单样式等配置项，详细参考下表，若要全局修改则写在src/plugins/EasyComponent/globalConfig.js  | Object  | -  | - |
|  buttons  |  定义表单下方的按钮，详细参考下表  | Array  | -  | - |
|  meta  |  一些自定义的原信息，会在使用闭包或调用按钮时在作用域中返回，一般用于多个Easy组件公用方法时区别不同的调用来源  | Object  | -  | - |

## 组件参数-fields

fields是一个对象数组，用于定义每个表单项的属性。除了通用字段外，不同的type会有部分额外的字段。

|  属性名   | 说明  | 类型 |  可选值 |  默认 |
|  ----  | ----  | ----  | ---- | ----  |
| prop  | 表单项的主键，请设置为唯一，最终的表单对象中使用的字段名，能够使用"sonObj.name"这种路径形式的值，将会自动转换会表单返回值的层级 | string | - | - |
| key  | 用于某些不存在prop项的主键 | string | - | - |
| label  | 字段的中文名称，用于显示表单项和校验提示 | string | - | - |
| showColon  | 是否在label中追加冒号 | boolean | - | - |
| type  | 规定表单项使用的组件，部分type会有额外的属性项 | string | divider/view/input/select/date-picker/radio/checkbox/upload/slot | - |
| isView  | 强制设置type为view | boolean | - | - |
| slotName  | type为slot或divider时，会替换该具名插槽到对应位置 | string | - | - |
| span  | 同row-col中的span，用于珊格布局，type为divider时span强制为24 | string/number | - | - |
| empty  | 生成一个空的组件，一般和span搭配用于占位 | boolean | - | false |
| required  | 是否必填，自动生成中文rule和必填提示星号 | boolean | - | false |
| rules  | 同el-table的校验写法 | Array | - | - |
| showInForm  | 是否在表单中显示，需要显示的表单项都要设置为true，当为false时，最终提交的表单将不会包含该字段 | boolean | - | false |
| keepOnForm  | 当showInForm为false时提交时依然保留该字段 | boolean | - | false |
| formSort  | 表单项排序 | number | - | 0 |
| fieldTips  | 用于生成校验提示和placeholder | string | - | 请录入 |
| defaultValue  | 当对应的表单项为undefined时初始化的值，当type中为多选等数组时需要通过该属性把默认值设置为空数组 | Function(scope, value) | - | - |
| valueFormat  | 表单校验成功后会调用该方法进行格式化 | Function(scope, value) | - | - |
| praseValue  | 表单初始化时调用该方法格式化字段，一般用于表单回现服务端的数据 | Function(scope, value) | - | - |
| formItemProp  | 传递el-form-item的参数 | Object | - | - |
| formProps  | 直接传递给表单组件的参数，如disabled等 | Object | - | - |
| formListeners  | 直接传递给表单组件的监听器 | Object | - | - |
| styles  | 分别传递到对应的col和formItem的style上 | Object<{ col: Object, formItem: Object }> | - | - |
| trim  | 是否在提交时清除字符串两端的空格，仅在调用getParseFormData或submitForm且值类型为字符串的时候生效，优先级高于formConfig.trim | boolean | - | true |
| append  | type 为 input 时可用，添加在输入框后面的单位 | string | - | - |
| options  | type 为 select/radio/checkbox 时可用，选项，下方查看[详细用法](#选项-options) | Array<{ value: any, label: string, disabled: boolean | Function }> | - | [] |
| useRadioButton  | type 为 radio 时可用，将单选样式设置为按钮 | boolean | - | - |
| disableValidates  | 禁用校验规则 | boolean | - | - |
| labelSlotName  | label插槽名称 | string | - | - |

## 组件参数-formConfig

该属性是一个对象，用于配置表单的样式和功能等

|  属性名   | 说明  | 类型 |  可选值 |  默认 |
|  ----  | ----  | ----  | ----  | ----  |
| labelPosition  | 表单域标签的位置，如果值为 left 或者 right 时，则需要设置 label-width | string | right/left/top | right |
| labelWidth  | 表单域标签的宽度，例如 '50px'。作为 Form 直接子元素的 form-item 会继承该值。支持 auto。 | string | - | - |
| showColon  | 是否在label中追加冒号 | boolean | - | - |
| readOnly  | 设置表单为只读不可编辑状态 | boolean | - | false |
| gutter  | 分栏间隔 | number | - | 0 |
| buttonPosition  | 下方按钮位置 | string | left/center/right | - |
| showSubmit  | 是否显示提交按钮，点击会进行表单校验，校验成功后抛出submit事件 | boolean | - | false |
| showCancel  | 是否显示取消按钮，点击后抛出cancel事件 | boolean | - | false |
| showValidMessage  | 校验失败时是否显示校验通知 | boolean | - | true |
| trim  | 是否在提交时清除字符串两端的空格，仅在调用getParseFormData或submitForm且值类型为字符串的时候生效，优先级低于field.trim | boolean | - | true |
| isView  | 强制设置所有field的type为view | boolean | - | - |
| disableValidates  | 禁用所有校验规则 | boolean | - | - |
| labelSlotName  | label插槽名称 | string | - | - |


## 组件参数-buttons

该属性是数组，用于定义表单下方的按钮

|  属性名   | 说明  | 类型 |  可选值 |  默认 |
|  ----  | ----  | ----  | ----  | ----  |
| label  | 按钮文本 | string | - | - |
| show  | 是否显示该按钮 | boolean | - | - |
| type  | 同el-button的type | string | primary / success / warning / danger / info / text | - |
| size  | 同el-button的size | string | medium / small / mini | - |
| disabled  | 是否禁用 | boolean | - | - |
| loading  | 是否加载中 | boolean | - | - |
| handler  | 点击时触发的回调 | Function(scope, button) | - | - |

## 组件实例方法-Methods

可以通过ref或者button的回调方法获取组件实例

|  方法名   | 说明  | 入参 |  返回值 |  说明 |
|  ----  | ----  | ----  | ----  | ----  |
| submitForm  | 校验表单 | - | Promise.resolve(formData)\Promise.reject(rules) | 成功时返回表单值，失败抛出校验结果，并根据配置弹出提示，返回的表单已经过valueFormat属性格式化 |
| getParseFormData  | 不进行校验直接获取经过valueFormat属性格式化的表单 | - | Object | - |
| resetFormData  | 重置表单为传入的值，不传入则全部重置为空 | Object(可选) | - | - |
| clearValidate  | 清除校验提示 | - | - | - |

## 选项-options

type为部分值时field接收一个额外的options
属性用于定义选项

```javascript
const fields = [
  {
    // 用法1 传入对象数组
    type: 'select',
    prop: 'test-select-1',
    label: '测试选项1',
    options: [
      {
        label: '一', // 展示的名称
        value: '1', // 最终输入到表单的值
        disabled: (scope)=>{
          return false
        }
      }
    ]
  },
  {
    // 用法2 传入基础值数组
    type: 'select',
    prop: 'test-select-2',
    label: '测试选项1',
    options: ['1']
  }
]

```

## 进阶-闭包

大部分情况下，上面这些属性都可以通过闭包的方式根据组件状态进行响应式设置(部分不生效的是因为暂时没有需要用到的场景，用到再往组件里加)，闭包的第一个参数必定为scope，这个对象分别可以解构出formData、formConfig、formInstance、meta，部分属性的闭包会追加传入额外的参数，请参考下面的文档或源代码

```javascript
// 普通静态配置
const fields = [
  {
    type: 'input',
    prop: 'name',
    label: '姓名',
    showInForm: true
  }
]
```
```javascript
// 使用闭包
const fields = [
  {
    type: 'input',
    prop: 'name',
    label: '姓名',
    showInForm: ({ formData, formConfig, formInstance, meta })=>{
      // 仅当表单中x字段等于1才会显示姓名字段
      // 尽量不要在此处修改scope内各项的值，否则大概率会栈溢出
      return formData.x === '1'
    }
  }
]
```

### 闭包中不支持异步操作  

需要异步操作时请用闭包返回一个当前组件的值，然后异步去改变这个值

```javascript
export default {
  data(){
    return {
      asyncArray: [],
      fields: [
        {
          type: 'radio',
          prop: 'needNum',
          label: '是否填写人数',
          showInForm: true,
          span: 12,
          required: true,
          options: [
            { label: '是', value: '1' },
            { label: '否', value: '0' }
          ],
          formListeners: ({ formData })=>{
          // formListeners这种也可以使用闭包获取组件状态
            return {
              change: (value)=>{
                // 把formData.needNum作为formData.testSelect的选项
                this.asyncArray = [formData.needNum]
              }
            }
          }
        },
        {
          type: 'select',
          prop: 'testSelect',
          label: '异步动态的选项',
          defaultValue: [],
          required: true,
          showInForm: true,
          span: 12,
          options: ({ formData }, formProps) => {
            return this.asyncArray
          }
        }
      ]
    }
  },
  created(){
    setTimeout(()=>{
      this.asyncArray = ['异步选项']
    }, 5000)
  }
}

```

## 进阶-使用插槽

通过type不能实现需要的效果的时候，可以通过定义具名插槽插入到fields数组定义的相应的位置

```html
<easy-form :form-config="formConfig" :fields="fields">
  <div 
    slot="opscope"
    slot-scope="scope" 
  >
    <!-- scope包含了formData和field两个对象 -->
    <el-input 
      v-model="scope.formData[scope.field.prop]" 
      disabled 
    />
    <el-button type="primary">选择经营范围</el-button>
  </div>
</easy-form>
```

```javascript
const fields = [
  {
    type: 'slot',
    span: 24,
    label: '经营范围',
    showInForm: true,
    slotName: 'opscope', // 对应插槽的slot字段
    prop: 'opscope'
  }
]
```

## 组件完整使用例子

```javascript
export default {
  data() {
    return {
      formData: {},
      formConfig: {
        labelPosition: 'left',
        labelWidth: '130px',
        gutter: 20,
        showSubmit: true, // 是否显示预设的提交按钮
        showCancel: true,
        buttonPosition: 'right', // 页脚按钮位置
        showValidMessage: true // 校验失败时是否使用Message显示提示错误消息
      },
      fields: [
        {
          type: 'input',
          prop: 'name',
          label: '数量',
          isView: (scope) => {
            return false
          }, // 忽略type属性使用不可编辑的展示模式
          showInForm: true, // 是否显示在表单中
          append: '个',
          formSort: 0,
          defaultValue: () => { // 初始化时当前项为undefined时调用
            return []
          },
          valueFormat: (scope, value) => { // 调用submitForm时会调用这个方法获取parseFormData
            return value + 1
          },
          praseValue: (scope, value) => { // 表单初始化时调用该方法进行格式化值，当调用defaultValue时不会再调用此项
            return typeof value === 'string' ? value.split(',') : value
          },
          span: 12, // 同el-row
          required: true, // 自动生成中文错误提示
          rules: [
            { validator: (rule, value, callback) => {
              callback(value > 5 ? '数量不能大于5' : undefined)
            }, trigger: 'blur' }
          ]
        },
        {
          type: 'select',
          prop: 'sex',
          label: '性别',
          defaultValue: '1',
          required: true,
          options: (scope, formData) => {
            return [
              { label: '男', value: '1' },
              {
                label: '女',
                value: '0',
                disabled: (scope, formData) => {
                  return true
                }
              }
            ]
          },
          showInForm: true,
          span: 12,
          rules: []
        },
        {
          type: 'divider', // 分割线，自动占一行
          label: 'test divider',
          prop: 'divider-1',
          contentPosition: 'center',
          showInForm: true
        },
        {
          type: 'date-picker',
          prop: 'date',
          label: '日期',
          required: true,
          showInForm: true,
          span: 12,
          praseValue: (scope, value) => {
            return new Date(value)
          },
          formProps: {
            type: 'date',
            valueFormat: 'yyyy-MM-dd'
          },
          rules: []
        },
        {
          type: 'radio',
          prop: 'radio',
          label: '单选',
          showInForm: true,
          required: true,
          formProps: {
            'value-key': 'a'
          },
          options: (scope, formData) => {
            return [
              { label: '男', value: { a: '1' } }, // 当value是对象时需要在formProps指定value-key
              { label: '女', value: { a: '0' } }
            ]
          },
          span: 24,
          rules: []
        },
        {
          type: 'checkbox',
          prop: 'checkbox',
          label: '多选',
          showInForm: true,
          required: true,
          fieldTips: '请选择',
          defaultValue: () => {
            return []
          },
          options: (scope, formData) => {
            return [
              { label: '多选A', value: '2' },
              { label: '多选B', value: '1' },
              { label: '多选C', value: '0' }
            ]
          },
          span: 24,
          rules: []
        },
        {
          type: 'slot',
          showInForm: true,
          slotName: 'testSlot',
          span: 12
        }
      ],
      buttons: [ // 页脚追加的按钮
        {
          label: '取消',
          type: 'danger',
          loading: false,
          handler: (scope, button) => {
            console.log(scope, button)
            button.loading = true
            button.label = '正在取消'
            setTimeout(() => {
              button.loading = false
              button.label = '取消'
            }, 5000)
          }
        }
      ]
    }
  },
  methods: {
    onSubmit(formData) {
      console.log('检验成功', formData)
    },
    onValid(rules) {
      console.log('检验失败', rules)
    }
  }
}
```
