重生之我使用vue3+element写出了formTable(验证表格验证)[附源码]

我重生了 校霸抽。。。咳咳错了。。。我重生了 使用vue3实现制作验证表格、
老规矩 先上图(最后附带源码)
在这里插入图片描述

看起来简单就是单纯的form套table,nonono里面有门道的,且听我娓娓道来
(那个。。。刚重生代码水平不太行,目前封装的只是实现了功能,但是感觉还有优化的空间,不知道咋优化,大佬们给点意见,球球你们了 /流泪)

首 先 4 个 问 题
1、form怎么写
2、值,以及验证的值怎么绑定
3、必填的时候表头展示
4、不同组件库怎么切换
5、新增和删除和验证数据
6、源码以及,组件化使用

1、form怎么写

table单元格内容的校验可以通过插槽的写法进行form的插入
在这里插入图片描述
普通的input样式就是这样的可以实现验证

2、值,以及验证的值怎么绑定

通过设置 :prop=" ‘tableData.’ + scope.$index + ‘.tel’ "可以实现校验值的绑定
tableDtata要放在form里面嗷
在这里插入图片描述
在这里插入图片描述

3、必填的时候表头展示

表头的展示 是通过:header-cell-class-name=‘addHeaderCellClassName’ 添加指定类名来实现带红点的效果
在这里插入图片描述

_props.requird为父组件传进来的需要验证的表头

<script>
function addHeaderCellClassName({ row, column, rowIndex, columnIndex }) {
    //_props.requird为父组件传进来的需要验证的表头  格式 :['材料名称', '型号', '进场数量']
	if (_props.required.includes(column.label)) {
		return 'requiredClass'
	}
}
</script>
<style lang="scss" scoped>
:deep(.requiredClass .cell::before) {
	content: "*";
	color: #f56c6c;
	margin-right: 4px;
}
</style>

4、不同组件库怎么切换

通过vue的内置组件component和slot实现标签的动态切换
在这里插入图片描述

5、新增和删除数据

在这里插入图片描述

// 新增数据
function onAddTableLine(value) {
	form.value.tableData.push(value||{});
}
// 删除数据
function onRemoveTableLine() {
	form.value.tableData = form.value.tableData.filter(
		(item) => !multipleSelection.value.some((i) => i == item)
	);
}
// 验证表单
const valiDate = (call) => {
	_FormRef.value.validate((valid, fields) => {
		console.log(valid, fields)
	})
};

6、源码以及,组件化使用

<template>
	<div>
		<!-- 调试使用 -->
		<!-- <el-button type="primary" @click="valiDate">校验规则</el-button>
		<el-button type="primary" @click="onAddTableLine">新增</el-button>
		<el-button type="warning" @click="onRemoveTableLine">删除</el-button> -->
		<el-form ref="_FormRef" :model="form">
			<el-table :data="form.tableData" border style="width: 100%; margin-top: 20px" row-key="id"
				:header-cell-class-name='addHeaderCellClassName' ref="tableRef" @selection-change="handleSelectionChange">
				<el-table-column type="selection" width="55" />
				<el-table-column v-for="(option, index) in options" :key="index" :label="option.label">
					<template v-if="option.npFormSlot" #default="scope">
						<slot :name="option.npFormSlot" :row="scope" />
					</template>
					<template v-else #default="scope">
						<el-form-item :prop="'tableData.' + scope.$index + '.' + option.prop" :rules="rules[option.prop]">
							<slot :name="'default'" :item="{ option, tableData, changeDataHandler }">
								<el-date-picker v-if="option.tag == 'date-picker'" v-model="scope.row[option.prop]"
									:type="option.pickerType || 'date'" :format="option.format || 'YYYY/MM/DD'"
									:value-format="option.format || 'YYYY-MM-DD'" :disabled="option.disabled" />
								<component v-else :is="`el-${option.tag}`" :type="option.type || 'txt'" v-model="scope.row[option.prop]"
									:disabled="option.disabled">
									<template v-if="option.options">
										<el-radio v-if="option.tag == 'radio-group'" v-for="i in option.options" :key="i.value"
											:label="i.value" size="large">{{ i.label }}</el-radio>
										<el-option v-else v-for="item in option.options" :key="item.value" :value="item.value"
											:label="item.label">
											{{ item.label }}
										</el-option>
									</template>
								</component>
								<div class="disableBox" v-if="option.disableBox">
									{{ scope.row[option.prop] }}
								</div>
							</slot>
						</el-form-item>
					</template>
				</el-table-column>
			</el-table>
		</el-form>
	</div>
</template>
<script setup>
import { ref, toRefs, watch, defineExpose, shallowRef } from "vue";
const _props = defineProps({
	Data: {
		type: Object,
		default: () => ({})
	},
	options: {
		type: Array,
		required: true
	},
	required: {
		type: Array,
		default: []
	}
})
const _emit = defineEmits(["updateFormData"]);
const multipleSelection = ref([]);
const form = ref({
	tableData: _props.Data
})
const tableRef = shallowRef();
const rules = mergeRule(_props.options || []);

watch(
	() => form.value.tableData,
	() => {
		console.log('监听到变化')
		_emit("updateFormData", form.value.tableData);
	},
	{ deep: true }
);
/**
 * 改变formData的数据
 * @param prop 属性名
 * @param value 属性值
 */
function changeDataHandler(prop, value) {
	console.log("插槽回调");
	// formData.value[prop] = value;
}

const _FormRef = ref();
/**
 * 验证表单
 * @param call
 */
const validate = (call) => {
	return _FormRef.value?.validate(call);
};


/**
 * 操作el-form ref提供的方法及属性
 * @param call
 */
const doFormRef = (call) => {
	call(_FormRef.value);
};

// 清除表单验证
function clearValidate() {
	_FormRef.value.clearValidate();
}

defineExpose({
	validate,
	doFormRef,
	clearValidate,
	onAddTableLine,
	onRemoveTableLine,
	form,
});
// 新增数据
function onAddTableLine(value) {
	form.value.tableData.push(value||{});
}
// 删除数据
function onRemoveTableLine() {
	form.value.tableData = form.value.tableData.filter(
		(item) => !multipleSelection.value.some((i) => i == item)
	);
}
// 测试-验证表单
const valiDate = (call) => {
	_FormRef.value.validate((valid, fields) => {
		console.log(valid, fields)
	})
};
// 选择表格数据
const handleSelectionChange = (val) => {
	multipleSelection.value = val;

};
function addHeaderCellClassName({ row, column, rowIndex, columnIndex }) {
	if (_props.required.includes(column.label)) {
		return 'requiredClass'
	}
}
/**
 * 合并formItem 的rules
 * @param formItem
 */
function mergeRule(formItem) {
	const rules = {}
	formItem.forEach(item => {
		if (Array.isArray(item.rule) && item.rule?.length > 0) {
			rules[item.prop] = item.rule
		}
	})
	return rules
}
</script>
<style lang="scss" scoped>
:deep(.requiredClass .cell::before) {
	content: "*";
	color: #f56c6c;
	margin-right: 4px;
}
</style>

在这里插入图片描述
附带插槽写法
在这里插入图片描述

option参数参考 (:required上面已经提到过了 这里就不详细说了哈哈哈哈 string[ ]格式嗷~)

:required =“[‘材料名称’, ‘型号’, ‘进场数量’]”

   cosnt data =  [{
      label: '问题类型',
      prop: 'issueType',
      tag: 'select',
      options: [
        { label: '是', value: 1 },
        { label: '否', value: 0 }
      ],
    },
    {
      label: '问题说明',
      prop: 'issueDescription',
      tag: 'input',
      rule: [
        {
          required: true,
          message: "请输入问题说明",
          trigger: "change",
        },
      ],
    },
    {
      label: '问题发现人',
      prop: 'required',
      disableBox: true
    },
    {
      label: '附件',
      prop: 'question',
      npFormSlot: 'button'
    },]
父组件中的调用
// formTable新增数据
const onAddTableLine = () => {
  _formTableChild.value.onAddTableLine()
}
// formTable删除数据
const onRemoveTableLine = () => {
  _formTableChild.value.onRemoveTableLine()
}
// 子组件回调
const upDataFormTable = (val) => {
  console.log(val)
  formData.value.createXMProjectPatrolCheckItemList = val
}
// 父组件进行表单验证
const _formTableChildVerify = async () => {
  return await _formTableChild.value.validate((valid) => {
    console.log(valid);
  });
};

有这种需求可以这样传参~
在这里插入图片描述

// formTable新增数据
const onAddTableLine = () => {
	_formTable.value.onAddTableLine({ required: '张三' })
}

哎呀,体力不支了,今天的代码就先到这里吧,明天依然是光芒万丈

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值