介绍
mc-form
,一个表单通用组件,目的是通过一份配置文件生成一个表单,减少重复性的工作。由于mc-form
产生于雪花项目,所以很多默认配置都是按照雪花项目的来。例如,生成一个包含输入框和选择框的表单配置如下:
const config = {
gutter: 20,
labelWidth: '120px',
properties: [
{
field: 'code',
value: null,
label: '门店编码',
type: 'text',
ui: {
column: 12
}
},
{
field: 'type',
value: null,
label: '门店类型',
type: 'select',
ui: {
column: 12
},
options: {
data: [
{
label: '春纪',
value: 1
},
{
label: '丸美',
value: 2
}
]
}
}
]
};
<mc-form :config="config"></mc-form>
安装
npm install mc-form -S
使用
import Vue from 'vue';
import McForm from 'mc-form';
Vue.component(McForm.name, McForm);
关于dx表达式
dx表达式的存在是为了实现数据关联的效果。例如,当某字段为空时不允许编辑 disabled: 'dx:{{ !$state.field }}'
,具有以下特点:
- 格式如:'dx:{{ expression }}'
- 特殊字段
$state
代表表单(el-form
)的model
对象 - 不允许赋值的存在,比如 'dx{{ $state.name = 1 }}'是不合法的
组件属性: config
mc-form
的配置文件,根据该配置生成表单
{
gutter: 10,
labelWidth: '80px',
state: {},
properties: []
}
表单项配置: config.properties
config.properties
为数组,里面包含了各种表单项的相关配置对象。通用字段如下:
{
type: 'text|number|password|select|checkbox|radio|time|year|month|date|dates|week|datetime|datetimerange|daterange|monthrange|selector|editor|inputrange|upload|tree|component',
field: 'field',
label: 'label',
value: 'value',
ui: {
column: 24,
size: 'mini',
wrap: false,
aequilate: false,
occupation: true,
hidden: false,
disabled: false,
readonly: false,
clearable: false,
placeholder: '',
labelWidth: ''
},
linkeds: [
{
path: 'field',
value: 'dx:{{ [] }}',
refresh: true
}
],
rules: [
{ required: true, message: '必填', trigger: 'change'}
]
}
1. 文本框
{
type: 'text|number|password',
field: 'field',
value: null,
label: '文本框'
input: {
rows: 2,
autosize: false
}
}
2. 单选框
{
type: 'radio',
field: 'field',
value: null,
label: '单选框',
options: {
data: [ { label: '是', value: 1 } ] || 'state.DICT.dict.vipLevels',
label: 'label',
value: 'value',
ajax: {
request: (data, params) => Promise.reolve([]),
auto: true,
url: '/url',
params: {
id: 'dx:{{ $state.id }}'
},
data: {
name: 'dx:{{ $state.name }}'
},
method: 'post',
beforeSend: 'dx:{{ !!$state.parentId }}',
path: 'data.content || data.recordList'
},
include: [],
exclude: []
},
}
3. 多选框
{
type: 'checkbox',
field: 'field',
value: null,
label: '多选框',
options: {
data: [ { label: '是', value: 1 } ] || 'state.DICT.dict.vipLevels',
label: 'label',
value: 'value',
ajax: {
request: (data, params) => Promise.reolve([]),
auto: true,
url: '/url',
params: {
id: 'dx:{{ $state.id }}'
},
data: {
name: 'dx:{{ $state.name }}'
},
method: 'post',
beforeSend: 'dx:{{ !!$state.parentId }}',
path: 'data.content || data.recordList'
},
include: [],
exclude: [],
checkAll: true
},
}
4. 选择框
{
type: 'select',
field: 'field',
value: null,
label: '选择框',
options: {
data: [ { label: '是', value: 1 } ] || 'state.DICT.dict.vipLevels',
label: 'label',
value: 'value',
ajax: {
request: (data, params) => Promise.reolve([]),
auto: true,
url: '/url',
params: {
id: 'dx:{{ $state.id }}'
},
data: {
name: 'dx:{{ $state.name }}'
},
method: 'post',
beforeSend: 'dx:{{ !!$state.parentId }}',
path: 'data.content || data.recordList'
},
include: [],
exclude: [],
additional: {
[label]: 'label',
[value]: 'value'
}
},
select: {
filterable: false,
multiple: false,
remote: false
}
}
5. 日期时间选择器
{
type: 'time|year|month|date|dates|week|datetime|datetimerange|daterange|monthrange',
field: 'field',
value: null,
label: '日期选择器',
picker: {
editable: false,
startPlaceholder: '',
endPlaceholder: '',
format: null,
rangeSeparator: '-',
valueFormat: 'timestamp',
pickerOptions: null,
isRange: false,
arrowControl: false,
}
}
6.选择器
该组件是为了类似于点击按钮,出现弹窗后选择
的类似需求,需要配合setState
和selector.event
使用。界面形式为左边el-tag
,右边el-button
{
type: 'selector',
field: 'field',
value: null,
label: '日期选择器',
selector: {
label: 'label',
type: 'primary',
text: '选择',
size: 'medium',
event: 'click',
closable: true,
}
}
7. 富文本
需要额外安装mc-form-editor组件
{
type: 'editor',
field: 'field',
value: null,
label: '富文本',
editor:{
menus: [
'head',
'bold',
'fontSize',
'fontName',
'italic',
'underline',
'strikeThrough',
'foreColor',
'backColor',
'list',
'justify',
'image'
],
colors: [
'#000000',
'#eeece0',
'#1c487f',
'#4d80bf',
'#c24f4a',
'#8baa4a',
'#7b5ba1',
'#46acc8',
'#f9963b',
'#ffffff'
],
zIndex: 9,
path: 'content',
uploadURL: null,
uploadFileName: 'file',
uploadImgShowBase64: false,
uploadImgMaxSize: 1 * 1024 * 1024,
}
}
8. 文本范围
{
type: 'inputrange',
field: 'field',
value: null,
label: '文本范围',
inputrange: {
startPlaceholder: '',
endPlaceholder: '',
rangeSeparator: '-',
type: 'number'
}
}
9. 图片上传
{
type: 'upload',
field: 'field',
value: null,
label: '图片上传',
upload: {
accept: 'image/jpeg,image/jpg,image/png',
action: '',
headers: {},
multiple: false,
name: 'file',
limit: 0,
tip: '',
limitSize: 1,
onSuccess: res => ({ success: res.code === 200, message: res.chnDesc, uri: res.content })
}
}
10. 树
抱歉,尚未实现异步加载
{
type: 'tree',
field: 'field',
value: null,
label: '树',
tree: {
data: [] || 'state.USER.user.permissionTree',
emptyText: '暂无数据',
nodeKey: 'id',
props: {
label: 'label',
children: 'children'
},
highlightCurrent: false,
defaultExpandAll: false,
expandOnClickNode: true,
checkOnClickNode: false,
autoExpandParent: true,
checkStrictly: false,
accordion: false,
leafOnly: false,
includeHalfChecked: false,
deep: false
}
}
11. 纯文本
纯文本,可用于写个表头或者描述性文本
{
type: 'plaintext',
plaintext: {
align: 'center',
text: '',
clsName: ''
}
}
12. 自定义组件
众所周知,产品的需求是相当骚的,为了实现某些骚操作,开放自定义组件的功能供开发者使用。
{
type: 'component',
component: Component
}
使用自定义组件可接受以下 props: ['state', 'gutter']
。同时,由于自组件不能修改父组件的数据,需要额外$emit,不能舒舒服服的用v-model
,请自行衡量。
this.$emit('update:object', this.state, 'name', '刘伟健');
this.$emit('update:object', this.state, { name: '刘伟健' });
this.$emit('update:array', this.state.users, 'push', { name: null, sex: null });
当然,如果觉得以上写法麻烦,版本支持的情况下可以使用使用inject: ['dangerousState']
,与this.state
等价
修改默认配置
由于默认配置不太适合于其他项目,所以提供一个可修改默认配置的方法
import instance from '@http/instance';
import McForm, { setDefaultConfigs } from 'mc-form';
export default function install(Vue) {
Vue.component(McForm.name, McForm);
setDefaultConfigs({
request: instance,
upload: {
onSuccess: res => ({ success: false, message: 'error' })
};
});
}
组件方法
{
getState(field) {},
validate() {},
clear() {},
setState(field, value, isReset) {},
setEditable(field, prop, expr) {},
setOptions(field, prop, options) {},
reset() {}
}
关于请求缓存
对于某些请求,例如获取省市区,我们希望能够缓存起来不做二次请求。考虑到mc-form
不能进行全局缓存,所以便不支持。但是开发者者可以在ajax.options.request
上做处理。以下为丸美实现全局缓存的例子,仅供参考:
export function createCaches(fn, prop) {
let caches = {};
let cb = function _cache(params) {
let key = params[prop];
if (isEmptyValue(key)) {
return Promise.reject(new Error(`params.${prop} is required`));
}
if (!caches[key]) {
caches[key] = fn.call(this, params).catch(e => {
delete caches[key];
return Promise.reject(e);
});
}
return caches[key];
};
cb.clear = function(key) {
isEmptyValue(key) ? (caches = {}) : (delete caches[key]);
};
return cb;
}
const requestRegions = createCaches(data => $http.post('/base_data/areas:search', data.parentId === 'TOP' ? {} : data), 'parentId');
const config = {
properties: [
{
label: '省市区',
type: 'select',
field: 'provinceId',
value: null,
ui: {
column: 8
},
options: {
ajax: {
request: requestRegions,
data: {
parentId: 'TOP'
}
},
label: 'name',
value: 'id'
},
linkeds: [
{
path: 'cityId',
value: null,
refresh: true
}
]
},
{
label: '',
type: 'select',
field: 'cityId',
value: null,
ui: {
column: 4
},
options: {
ajax: {
request: requestRegions,
data: {
parentId: 'dx:{{ $state.provinceId }}'
},
beforeSend: 'dx:{{ !!$state.provinceId }}'
},
label: 'name',
value: 'id'
},
linkeds: [
{
path: 'countyId',
value: null,
refresh: true
}
]
},
{
label: '',
type: 'select',
field: 'countyId',
value: null,
ui: {
column: 4
},
options: {
ajax: {
request: requestRegions,
data: {
parentId: 'dx:{{ $state.cityId }}'
},
beforeSend: 'dx:{{ !!$state.cityId }}'
},
label: 'name',
value: 'id'
}
}
]
}