组成:form的index.vue + 逻辑处理use-form.js+各个组件(input、select等).vue
使用:提供formItem.js
结果:
1、form的index.vue
<template>
<div class="hFormContainer">
<el-form ref="hForm" class="h-form" :model="_formData">
<el-row :gutter="20">
<el-col
v-for="(
{ prop, label, span, type, preSlot, sufSlot, rules }, index
) in formItems"
:key="prop"
:span="span || 5"
>
<el-form-item :label="label" :prop="prop" :rules="rules">
<!-- preSlot -->
<slot :name="preSlot"></slot>
<!-- input -->
<hInput
v-if="type === 'input'"
v-model="_formData[prop]"
:config="formItems[index]"
>
<template #inputPrefix>
<slot
:name="formItems[index].iptSufSlot"
:form-data="{ ..._formData }"
></slot>
</template>
<template #inputSuffix>
<slot
:name="formItems[index].iptSufSlot"
:form-data="{ ..._formData }"
></slot>
</template>
</hInput>
<!-- select -->
<hSelect
v-if="type === 'select'"
v-model="_formData[prop]"
:config="formItems[index]"
/>
<!-- datePick -->
<hDatePicker
v-if="type === 'datepick'"
v-model="_formData[prop]"
:config="formItems[index]"
/>
<!-- hCheckBox -->
<hCheckbox
v-if="type === 'checkbox'"
v-model="_formData[prop]"
:config="formItems[index]"
/>
<!-- radio -->
<hRadio
v-if="type === 'radio'"
v-model="_formData[prop]"
:config="formItems[index]"
/>
<slot :name="sufSlot"></slot>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</template>
<script setup>
import { useForm } from "./use-form";
import hInput from "./components/hInput/index.vue";
import hSelect from "./components/hSelect/index.vue";
import hRadio from "./components/hRadio/index.vue";
import hCheckbox from "./components/hChexkbox/index.vue";
import hDatePicker from "./components/hDatePicker/index.vue";
const props = defineProps({
formItems: Array,
});
const { _formData, getFormData, setFormData, resetFormData } = useForm(
props.formItems
);
defineExpose({
getFormData,
setFormData,
resetFormData,
});
</script>
<style lang="scss" scoped></style>
2、use-form.js
// 初始化所有的formItem
import { ref } from "vue";
const initFormDataHandle = (formItems) => {
const formData = {};
formItems.forEach(({ prop, initValue, type }) => {
if (type == "checkbox") {
formData[prop] = Array.isArray(initValue)
? initValue
: initValue
? [initValue]
: [];
} else {
formData[prop] = initValue || "";
}
});
};
export const useForm = (formItems) => {
const initFormData = initFormDataHandle(formItems);
// 接收
const _formData = ref({ ...initFormData });
const getFormData = () => ({ ..._formData.value });
// 外部传过来的formData
const setFormData = (formData, isReset) => {
_formData.value = isReset
? { ...formData }
: { ..._formData.value, ...formData };
};
const resetFormData = () => setFormData(initFormData, true);
return {
_formData,
getFormData,
setFormData,
resetFormData,
};
};
3、input
<script>
export default { name: "hInput" };
</script>
<script setup>
const props = defineProps({
modelValue: String,
config: Object,
});
const emit = defineEmits(["update:modelValue"]);
const input = (value, config) => {
emit("update:modelValue", validateField(value, config));
};
const validateField = (value, config) => {
let _value = value;
// 过滤空格
_value = _value.replace(/\s|[\r\n]/gi, "");
const reg =
// eslint-disable-next-line no-misleading-character-class
/([0-9|*|#]\uFE0F\u20E3)|([0-9|#]\u20E3)|([\u203C-\u3299]\uFE0F\u200D)|([\u203C-\u3299]\uFE0F)|([\u2122-\u2B55])|(\u303D)|([(A9)|(AE)]\u3030)|(\uA9)|(\uAE)|(\u3030)|([\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF])|([\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F])/g;
// 过滤表情
_value = _value.replace(reg, "");
// 只能输入数字和英文
// if (numberLetterFieldList.includes(id)) _value = _value.replace(/[\W]/g, '');
// 只能输入数字的输入框
if (config.number) _value = _value.replace(/[^\d]/g, "");
return _value;
};
</script>
<template>
<el-input
:model-value="modelValue"
v-bind="config"
:type="config.textAreaConfig ? 'textarea' : 'input'"
@update:model-value="(value) => input(value, config)"
>
<template v-if="config.preSlot" #prefix>
<slot name="inputPrefix"></slot>
<el-icon v-if="config.prefixIcon">
<component :is="config.prefixIcon" />
</el-icon>
</template>
<template #suffix>
<slot name="inputSuffix"></slot>
<el-icon v-if="config.prefixIcon">
<component :is="config.suffixIcon" />
</el-icon>
</template>
</el-input>
</template>
<style scoped lang="scss"></style>
4、select
<script setup>
const props = defineProps({
config: Object,
modelValue: String,
});
const emit = defineEmits(["update:modelValue"]);
const change = (value, config) => {
emit("update:modelValue", value, config);
};
</script>
<template>
<el-select
v-bind="config"
:model-value="modelValue"
filterable
clearable
@change="(value) => change(value, config)"
>
<el-option
v-for="item in config.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
<style scoped lang="scss">
.el-select {
width: 100%;
}
</style>
5、radio
<script setup>
const props = defineProps({
modelValue: String,
config: Object,
});
const emit = defineEmits(["update:modelValue"]);
const change = (value, config) => {
emit("update:modelValue", value);
};
</script>
<template>
<el-radio-group
:model-value="modelValue"
@change="(value) => change(value, config)"
>
<el-radio
v-for="{ label, value } in config.options"
:key="value"
:label="label"
>
{
{ label }}
</el-radio>
</el-radio-group>
</template>
<style scoped lang="scss"></style>
6、datePick
扫描二维码关注公众号,回复:
14633660 查看本文章
<script>
export default { name: "hDatePick" };
</script>
<script setup>
import { inject } from "vue";
const props = defineProps({
modelValue: String,
config: Object,
});
const emit = defineEmits(["update:modelValue"]);
const formInjectKey = Symbol();
const { setFormData } = inject(formInjectKey);
const change = (value) => {
if (Array.isArray(value)) {
const { startProp, endProps } = props.config;
setFormData({
[startProp || "startTime"]: value[0],
[endProps || "endTime"]: value[1],
});
}
emit("update:modelValue", value);
};
</script>
<template>
<div class="yn-date-pick-wrapper">
<el-date-picker
class="yn-date-pick"
v-bind="config"
:model-value="modelValue"
:type="config.dateType || 'daterange'"
:value-format="config.valueFormat || 'YYYY-MM-DD'"
@update:model-value="change(value)"
/>
</div>
</template>
<style scoped lang="scss">
.yn-date-pick-wrapper {
width: 100%;
:deep(.yn-date-pick) {
width: 100%;
.el-input__wrapper {
width: 100%;
box-sizing: border-box;
}
}
}
</style>
7、checkbox
<script>
export default { name: "hCheckbox" };
</script>
<script setup>
const props = defineProps({
modelValue: String,
config: Object,
});
const emit = defineEmits(["update:modelValue"]);
const checkAll = ref(false);
const isIndeterminate = ref(false);
const handleCheckAllChange = (val) => {
const value = val ? props.config.options.map((i) => i.value) : [];
isIndeterminate.value = false;
emit("update:modelValue", value);
};
const handleCheckedOptionChange = (value) => {
const checkedCount = value.length;
const optionCount = props.config.options.length;
checkAll.value = checkedCount === optionCount;
isIndeterminate.value = checkedCount > 0 && checkedCount < optionCount;
emit("update:modelValue", value);
};
</script>
<template>
<div class="checkbox-wrapper">
<el-checkbox
v-if="config.showCheckAll"
v-model="checkAll"
class="check-all block"
:border="config.border"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
>
{
{ config.checkAllText || "全选" }}
</el-checkbox>
<el-checkbox-group
:model-value="modelValue"
@change="handleCheckedOptionChange"
>
<el-checkbox
v-for="{ label, value } in config.options"
:key="value"
:border="config.border"
:label="value"
>
{
{ label }}
</el-checkbox>
</el-checkbox-group>
</div>
</template>
<style scoped lang="scss">
.checkbox-wrapper {
.check-all.block {
width: 100%;
}
}
</style>
使用form组件
1.提供formConfig
const hFormItem = [
{
type: "input",
label: "时间",
prop: "date",
},
{
type: "input",
label: "姓名",
prop: "name",
},
{
type: "input",
label: "地址",
prop: "address",
},
{
type: "select",
label: "状态",
prop: "status",
options: [
{ label: "成功", value: "1" },
{ label: "失败", value: "0" },
],
placeholder: "请选择状态",
},
{
type: "radio",
label: "性别",
prop: "sex",
options: [
{ label: "男", value: 0 },
{ label: "女", value: 1 },
],
},
];
export { hFormItem };
2、在对应的页面中使用
<template>
<hCard :title="tableConfig.title">
<template #top-right>
<el-button type="primary" @click="toSearch">搜索</el-button>
<el-button type="info" @click="resetGood">重置</el-button>
</template>
<template #bottom>
<hForm ref="goodForm" :formItems="hFormItem"> </hForm>
</template>
</hCard>
<hTable :tableData="tableData" v-bind="tableConfig">
<template #hTable-before-slot>
<el-button type="primary" size="small" @click="addGood()">新增</el-button>
</template>
<template #handle="{ row, column, index }">
<el-button link type="primary" size="small" @click="handleClick(row)"
>编辑</el-button
>
<el-button link type="primary" size="small" @click="deleteInfo(row)"
>删除</el-button
>
</template>
</hTable>
<hDialog v-model="dialogFormVisible" v-bind="dialogConfig">
<template #dialog-content>
<hForm ref="dialogForm" :formItems="formItems"></hForm>
</template>
</hDialog>
</template>
<script setup>
import hTable from "@/components/hTable/index.vue";
import hForm from "@/components/hForm/index.vue";
import hCard from "@/components/hCard/index.vue";
import hDialog from "@/components/hDialog/index.vue";
import tableConfig from "./goodConfig/tableConfig";
import { dialogConfig, formItems } from "./goodConfig/dialogConfig";
import { hFormItem } from "./goodConfig/formConfig";
import { nextTick, ref } from "vue";
const dialogFormVisible = ref(false);
const goodForm = ref(null);
const dialogForm = ref(null);
const tableData = [
{
date: "2016-05-03",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
status: 1, //1:待处理 0:已完成
sex: 1, //0 女 1男
},
{
date: "2016-05-02",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
status: 0, //1:待处理 0:已完成
sex: 0, //0 女 1男
},
{
date: "2016-05-04",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
status: 0, //1:待处理 0:已完成
sex: 1, //0 女 1男
},
{
date: "2016-05-01",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
status: 1, //1:待处理 0:已完成
sex: 0, //0 女 1男
},
];
// form
const toSearch = () => {
console.log(1212);
};
const resetGood = () => {
goodForm.value.resetFormData();
};
// table
const handleClick = (row) => {
const data = {
name: "张三",
};
dialogFormVisible.value = true;
nextTick(() => {
dialogForm.value.setFormData(data);
});
};
const deleteInfo = (row) => {
console.log(row);
};
const addGood = () => {
console.log(1212);
};
</script>
<style lang="scss" scoped></style>