前言: 进入正题之前请确保你已经学会element中的表单基本验证方法,如果不,这篇文章可能会让你感觉到有点吃力。
首先先讲明白思路
- 第一,把验证规则的trigger选项置空,防止它重复触发验证, 我们需要在我们自己的函数内手动触发验证。
- 第二,了解一点、关于动态标签的生成时,handlerInputConfirm与handlerClose 都会 触发一遍,这个是不可避免的。
- 第三,我们需要标签的长度,以作0个标签让表单不能通过。
rules 如下
technologyStack: [
{
required: true,
trigger: [],
validator: (rule: any, value: any) => {
if (tagLength.value == 0) {
return false;
} else {
return true;
}
},
message: "至少需要添加一个技术栈标签",
},
],
需要解决的tagLength
tag.vue组件
<script lang="ts" setup>
import { ref, nextTick, defineEmits } from "vue";
const inputVisible = ref(false);
const inputValue = ref("");
const addButtonShow = ref(true);
const dynamicTags = ref(new Array<string>());
const saveTagInput = ref();
const emit = defineEmits(["tagLength"]);
const handleInputConfirm = function () {
if (inputValue.value) {
dynamicTags.value.push(inputValue.value);
}
inputVisible.value = false;
inputValue.value = "";
if (dynamicTags.value.length == 5) {
addButtonShow.value = false;
}
emit("tagLength", dynamicTags.value.length);
};
const showInput = function () {
inputVisible.value = true;
nextTick(() => {
saveTagInput.value.input.focus();
});
};
const handleClose = function (tag: string) {
dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1);
if (!addButtonShow.value) {
addButtonShow.value = true;
}
emit("tagLength", dynamicTags.value.length);
};
</script>
<template>
<div class="tag-container">
<div class="tag-input">
<el-tag
v-for="tag in dynamicTags"
:key="tag"
closable
:disable-transitions="false"
@close="handleClose(tag)"
class="tag"
>
{{ tag }}
</el-tag>
<div style="display: flex;">
<el-input
v-if="inputVisible"
ref="saveTagInput"
v-model="inputValue"
class="input-new-tag"
size="mini"
maxlength="15"
@keyup.enter="handleInputConfirm"
@blur="handleInputConfirm"
>
</el-input>
<el-button
v-else
class="button-new-tag"
size="small"
v-show="addButtonShow"
@click="showInput"
>新增标签</el-button
>
</div>
</div>
<div class="tips" v-if="dynamicTags.length >= 5">自定义标签最多只能存在5个!</div>
</div>
</template>
<style lang="less" scoped>
.tag-container {
.tag-input {
display: flex;
flex-wrap: wrap;
}
.tag {
margin-right: 1rem;
margin-bottom: 0.5rem;
}
.tips {
color: red;
font-weight: bold;
margin-top: 0.3rem;
font-size: 0.8rem;
}
.button-new-tag {
height: 32px;
}
}
</style>
上面代码的重点在于emit 的定义以及发送,我们在生成的时候需要把当前动态标签的数组长度发送到我们需要的组件,删除也是同理。
在setupAPI中定义如下,因为我们emit(‘tagLength’,数组长度)把这个数组长度发送出去了,getTagLength相当于一个监听这个事件的监听器。 你可以把这种语法理解成Vue2的emit 跟on。
const tagLength = ref(0);
const getTagLength = function (val: number) {
tagLength.value = val;
console.log(tagLength.value);
// form表单 对特定字段进行验证。
demandForm.value.validateField("technologyStack");
};
OK,此时,如果你能准确的验证了,你会发现getTagLength这个函数被触发了两次,原因很简单,参考前面所说的第二点。如果你愿意尝试的话,也可以在表单规则的validator中 定义一个数量变量 去查看,它应该是没有任何多余的触发验证的,完全由我们控制。
效果
进行 两次 添加 一次 删除 后 的 数据展示如下
闲话
如果你想让你的setup 里面保持清爽简洁,将这个rules 移动到别的地方是不可避免的, 但这里又涉及到tagLength 这个我们需要在 组件里 的 ref,解决的思路是 导出一个函数。如:
const demandRules = ref(demandRulesImpl(tagLength));
// 表单规则
// 由于 其中有一个validator 需要监听到另一个组件的变化 所以以函数形式返回
export function demandRulesImpl(tagLength: Ref) {
return {
money: [
{ required: true, message: "请输入报酬,", trigger: "blur" },
{
pattern: /^[1-9][0-9]*$/,
message: "仅限正整数输入,同时不可为0",
trigger: "blur",
},
],
timeLimit: [{ required: true, message: "请选择解决方的限时时间", trigger: ["blur", 'change'] }],
backLimit: [
{ required: true, message: "请选择未解决时的退款时间", trigger: "blur" },
],
engineerType: [
{ required: true, message: "请选择方向上的工程师类型", trigger: ["blur", 'change'] },
],
technologyStack: [
{
required: true,
trigger: [],
validator: () => {
if (tagLength.value == 0) {
return false;
} else {
return true;
}
},
message: "至少需要添加一个技术栈标签",
},
],
}
}