BaseInput
根据配置生成iview基础表单组件
<template>
<component
v-bind="$attrs"
:is="inputType"
v-model="inputValue"
:style="defaultStyle"
:clearable="clearable"
:placeholder="$attrs.placeholder || autoPlaceholder(inputType)"
v-on="$listeners"
@input="(val) => $emit('changeValue', val)"
>
<component
:is="getChildrenType"
v-for="item in formatOptions"
:key="item.value"
:value="item.value"
:label="inputType === 'Select' ? item.label : item.value"
>
{{ item.label }}
</component>
</component>
</template>
<script>
export default {
name: "BaseInput",
model: {
prop: "value",
event: "changeValue",
},
props: {
value: {
type: [String, Array, Number, Date, Boolean],
default: null,
},
inputWidth: {
type: [String, Number],
default: "",
},
inputType: {
type: String,
default: "Input",
},
childrenOptions: {
type: [Array, Object, Function],
default: () => [],
},
clearable: {
type: Boolean,
default: true,
},
},
data() {
return {
inputValue: undefined,
};
},
computed: {
getChildrenType() {
const typeMap = {
RadioGroup: "Radio",
Select: "Option",
CheckboxGroup: "Checkbox",
};
return typeMap[this.inputType] || "";
},
defaultStyle() {
let width = this.inputWidth + "";
let inputList = ["Input", "Select", "DatePicker", "Cascader"];
if (inputList.includes(this.inputType)) {
if (width) {
let inputWidth = width.includes("px") ? width : width + "px";
return {
width: inputWidth,
};
} else {
return {
width: "100%",
};
}
}
return "";
},
formatOptions() {
if (typeof this.childrenOptions === "function") {
return this.formatOption(this.childrenOptions());
} else {
return this.formatOption(this.childrenOptions);
}
},
},
watch: {
value: {
handler (val) {
this.inputValue = val;
},
immediate: true
}
},
methods: {
autoPlaceholder(inputType) {
if (inputType.toLowerCase() === "input") {
return "请输入";
} else {
return "请选择";
}
},
formatOption(options) {
if (Array.isArray(options)) {
return options;
} else {
const arr = [];
for (const i in options) {
const obj = {
label: options[i],
value: i,
};
arr.push(obj);
}
return arr;
}
},
},
};
</script>
XForm
根据配置生成iview Form表单组件,支持render,slot,快捷表单校验等功能
<template>
<Form
ref="form"
:model="formValue"
v-bind="$attrs"
v-on="$listeners"
:rules="formRules"
>
<Row :gutter="16" class="row-wrap">
<slot name="preItem" />
<template v-for="item in options">
<Col v-if="item.key" :key="item.key" :span="item.colSpan || colSpan">
<template v-if="item.formSlotName && $scopedSlots[item.formSlotName]">
<slot :name="item.formSlotName" :data="formValue" :option="item" />
</template>
<template v-else>
<FormItem
:key="item.key"
:prop="item.key"
:label="item.itemLabel"
:label-width="item.itemLabelWidth"
v-bind="item.formItemOptions"
>
<template v-if="item.formRender">
<Render
:render="item.formRender"
:form-data="formValue"
:option="item"
/>
</template>
<template v-else>
<BaseInput
v-model="formValue[item.key]"
:inputWidth="inputWidth"
:form-value="formValue"
v-bind="getAttr(item)"
v-on="getListener(item)"
@on-change="setFormData"
/>
</template>
</FormItem>
</template>
</Col>
</template>
<slot />
</Row>
</Form>
</template>
<script>
import BaseInput from "./BaseInput.vue";
import _ from "lodash";
import Render from "./render";
export default {
name: "XForm",
components: {
BaseInput,
Render,
},
model: {
prop: "formData",
event: "formChange",
},
props: {
formData: {
type: Object,
required: true,
},
rules: {
type: Object,
default: () => {},
},
inputWidth: {
type: [String, Number],
default: "",
},
formOptions: {
type: [Array, Function],
default: () => [],
},
colSpan: {
type: String,
default: "24",
},
},
data() {
return {
formValue: {},
formRules: {}
};
},
computed: {
options() {
if (typeof this.formOptions === "function") {
return this.formOptions();
} else {
return this.formOptions;
}
},
},
watch: {
formData: {
handler (val) {
this.formValue = val;
},
immediate: true
},
formOptions: {
handler () {
let rules=this.getFormRules()
this.formRules={
...rules,
...this.rules
}
},
immediate: true
}
},
methods: {
getFormRules() {
let rules = {};
let InputTypeList = ["Input", "InputNumber"];
this.formOptions.forEach((item) => {
const prefix = InputTypeList.includes(item.inputType)
? "请输入"
: "请选择";
let message = item.message || prefix + item.itemLabel;
let trigger = InputTypeList.includes(item.inputType)
? "blur"
: "change";
if (item.required) {
rules[item.key] = [{ required: true, message, trigger }];
}
});
return rules;
},
setFormData() {
this.$emit("formChange", this.formValue);
},
isListener(key) {
//判断传入参数是否为事件
const preStr = key.substring(0, 2);
return preStr.toLowerCase() === "on";
},
formatListenerName(name) {
const str = name.charAt(2);
if (str === "-") {
return name;
} else {
return "on-" + name.substring(2).toLowerCase();
}
},
getAttr(item) {
const attrs = {};
for (const i in item) {
if (typeof item[i] !== "function") {
attrs[i] = item[i];
} else {
if (!this.isListener(i)) {
attrs[i] = item[i];
}
}
}
delete attrs.itemLabel;
delete attrs.itemLabelWidth;
delete attrs.formItemOptions;
delete attrs.key;
delete attrs.required;
delete attrs.message;
return attrs;
},
getListener(item) {
const listeners = {};
for (const i in item) {
if (typeof item[i] === "function") {
if (this.isListener(i)) {
listeners[this.formatListenerName(i)] = (...args) =>
item[i].call(this, ...args, this.formValue);
}
}
}
return listeners;
},
validate() {
return this.$refs.form.validate();
},
validateField(prop) {
return this.$refs.form.validateField(prop);
},
resetFields() {
this.$refs.form.resetFields();
this.$emit("formChange", this.formValue);
},
},
};
</script>
render.js
export default {
name: 'Render',
functional: true,
props: {
render: {
type: Function,
default: () => {}
},
option: {
type: Object,
default: () => {
return {}
}
},
formData: {
type: Object,
default: () => {
return {}
}
}
},
render: (h, ctx) => {
const params = {
option: ctx.props.option,
formData: ctx.props.formData
}
return ctx.props.render(h, params)
}
}