基于ElementPlus的Form组件封装

前言

我们在项目开发过程中遇到最多就是表单页面的开发,那么使用频率比较高的就是Form组件,无论是vue亦或者是react,我们在项目中使用到UI库都会有Form组件。多数情况下都是用到了Form组件,我们先根据UI库或者其他类似的页面直接进行ctrl+c、v操作,然后再进行修改,最终按照交互稿和视觉稿完成页面开发。这样做的弊端是,每次用到都需要重新写一遍,是不符合前端组件化的开发思想的。那么我们需要对Form组件进行二次封装,避免重复的代码书写,提高开发效率,增强代码的可读性和可扩展性。

介绍

本篇文章分享的是基于Element PlusForm组件的二次封装,为什么是Element Plus呢?因为正好我的项目中用到的是此UI库,项目中我对Form组件及逆行了二次封装,因为将这块的内容整理出来,输出一篇技术文档,希望对大家有帮助!UI库都是类似的,大家可以参照我的做法对其他UI库的Form组件进行封装。

技术栈

Vue3+Ts+Element Plus

效果图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

源码
// components/CForm/index.vue

<!--
    @author: duanfc
    @time: 2024-08-16 10:00:00
    @description: 描述
    @path: /demo
    @lastChange: duanfc
-->

<template>
	<el-form v-bind="$attrs" ref="elFormRef" class="el-form-style">
		<el-row :gutter="16">
			<slot name="formItem"></slot>
		</el-row>
	</el-form>
</template>

<script lang="ts">
import { ref } from "vue";
import type { ElForm } from "element-plus";

export default {
	name: "CForm",
	props: {},
	components: {},
	setup(props, context) {
		const elFormRef = ref<InstanceType<typeof ElForm> | null>(null);
		return {
			elFormRef,
		};
	},
};
</script>

<style lang="scss" scoped>
.el-form-style {
	width: calc(100% - 32px);
	margin-left: 16px;
	border-bottom: 1px solid #f0f0f0;
	.search-item:last-child {
		padding-right: 0 !important;
	}
	.search-item:first-child {
		padding-left: 0 !important;
	}
}
// 屏幕宽度小于992px
@media only screen and (max-width: 992px) {
	.search-item {
		padding: 0 !important;
	}
}
// 屏幕宽度大于等于992px但小于1200px
@media screen and (min-width: 992px) and (max-width: 1200px) {
	.search-item:nth-child(3n) {
		padding-right: 0 !important;
	}
	.search-item:nth-child(3n + 1) {
		padding-left: 0 !important;
	}
}
// 屏幕宽度大于等于1200px
@media screen and (min-width: 1200px) {
	.search-item:nth-child(4n) {
		padding-right: 0 !important;
	}
	.search-item:nth-child(4n + 1) {
		padding-left: 0 !important;
	}
}
</style>
// components/CFormItem/index.vue

<!--
    @author: duanfc
    @time: 2024-08-16 10:00:00
    @description: 描述
    @path: /demo
    @lastChange: duanfc
-->

<template>
	<el-col
		:md="baseSpan * span"
		:lg="baseSpan * span"
		:xl="baseSpan * span"
		:class="[isBtn ? 'btn-style' : '', 'search-item']"
		:offset="offset"
		v-show="formItemStatus"
	>
		<el-form-item v-bind="$attrs"><slot></slot></el-form-item>
	</el-col>
</template>

<script lang="ts">
import { computed, ref } from "vue";
import { useResize } from "@/layout/hooks/useResize";

export default {
	name: "cFormItem",
	components: {},
	props: {
		span: {
			type: Number,
			default: 1,
		},
		isBtn: {
			type: Boolean,
			default: false,
		},
		isExpand: {
			type: Boolean,
			required: true,
		},
		colTotal: {
			type: Number,
			default: 1,
		},
		itemIndex: {
			type: Number,
			required: true,
		},
	},
	setup(props, context) {
		const baseSpan = ref(0);

		// 计算按钮的offset值
		const calculateOffset = (
			val: number,
			colTotalValue: number,
			status: boolean
		): number => {
			if (val) {
				// 每一个筛选项的份数

				// 每行可放表单项的数量
				const itemSpan = 24 / val;
				// 最后一行筛选项的个数
				const remainder = colTotalValue % itemSpan;

				if (status) {
					// 展开状态

					if (screenWidth.value >= 992) {
						if (colTotalValue == 1) return 0;
						return (itemSpan - remainder - 1) * val;
					} else if (screenWidth.value < 992) {
						return 0;
					}
					// if (screenWidth.value >= 1200) {
					//     if (colTotalValue == 1) return 0;
					//     return (itemSpan - remainder - 1) * val;
					// } else if (screenWidth.value >= 992) {
					//     if (colTotalValue == 1) return 0;
					//     return (itemSpan - remainder - 1) * val;
					// } else if (screenWidth.value < 992) {
					//     return 0;
					// }
				} else {
					// 收起状态

					const itemSpan = 24 / val;
					const overNum = colTotalValue - itemSpan;
					if (screenWidth.value >= 1200) {
						if (colTotalValue < 4) {
							return (itemSpan - colTotalValue - 1) * val;
						}
						return overNum >= 3
							? 0
							: (itemSpan - overNum - 1) * val;
					} else if (screenWidth.value >= 992) {
						return overNum >= 2 || colTotalValue < itemSpan
							? 0
							: (itemSpan - overNum - 1) * val;
					} else if (screenWidth.value < 992) {
						return 0;
					}
				}
			}
		};

		const screenWidth = ref(0);

		// 表单项的显示与隐藏
		const formItemStatus = computed(() => {
			let bool = true;
			if (!props.isExpand) {
				if (screenWidth.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值