需求:根据type类型,动态检验abstract是否为必填项
效果图1
效果图2
效果图3
表单代码如下:
<el-form-item
label="Type:"
prop="articleType"
:rules="[
{
required: true,
message: 'Please Select Type',
trigger: 'change',
},
]"
>
<el-select
v-model="formData.articleType"
class="m-2"
placeholder="Select"
filterable
style="width: 1000px"
@change="handleArticleTypeChange"
>
<el-option
v-for="item in typeList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item
label="Abstract:"
prop="abstracts"
>
<template #label>
<span
v-if="isAbstractRequired"
style="color: red; margin-right: 4px;"
>*</span>
Abstract
</template>
<el-input
v-model="formData.abstracts"
:rows="9"
type="textarea"
style="width: 1000px"
/>
</el-form-item>
js代码如下:
const handleArticleTypeChange = (value) =>{
nextTick(() => {
if (formRef.value) {
formRef.value.validateField('abstracts');
}
});
}
const formDataRules = reactive({
abstracts: [ {
// required: false,
validator: checkAbstracts,
trigger: ["blur", "change"]
}]
})
const checkAbstracts = (rule, value, callback) => {
const currentType = formData.value.articleType;
// 如果没有选择文章类型,不进行校验
if (!currentType) {
callback();
return;
}
// 检查当前类型是否为可选摘要类型
const isOptionalType = optionalTypes.some(type =>
currentType.toLowerCase().includes(type)
);
// 如果是可选类型,直接通过校验
if (isOptionalType) {
callback();
return;
}
// 对于必填类型,检查摘要是否填写
if (!value || !value.trim()) {
callback(new Error("Please Input Abstract"));
} else {
callback();
}
};
const optionalTypes = ["editorial", "correspondence", "announcement", "commentary"];
// 判断是否必填
const isAbstractRequired = computed(() => {
const currentType = formData.value.articleType;
if (!currentType) return true;
return !optionalTypes.some(type =>
currentType.toLowerCase().includes(type)
);
});
补充另一个示例======================================
根据选择的reason来动态控制是否要设置为必填
<template>
<div class="distribute-rewards-modal">
<el-dialog
v-model="innerVisible"
title="Create New Rewards Distribution"
width="800px"
:close-on-click-modal="false"
@close="resetForm"
>
<el-form
:model="form"
:rules="rules"
ref="formRef"
label-width="180px"
>
<el-form-item label="Email" prop="email">
<el-input
v-model="form.email"
@blur="autoFillByEmail"
autocomplete="off"
/>
</el-form-item>
<el-form-item label="Name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="Reason" prop="reason">
<el-select v-model="form.reason" @change="handleReasonChange" style="width: 100%">
<el-option label="Behavior of sharing" value="Behavior" />
<el-option v-if="role === 'admin'" label="Other" value="Other" />
</el-select>
</el-form-item>
<el-form-item label="Sharing Channels" prop="sharingChannels">
<el-select v-model="form.sharingChannels" placeholder="Select" style="width: 100%">
<el-option
v-for="item in sharingChannelsList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="Sharing Type" prop="sharingType">
<el-select v-model="form.sharingType" placeholder="Select" style="width: 100%">
<el-option
v-for="item in sharingTypeList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="Journal" prop="journal">
<el-select v-model="form.journal" placeholder="Select" style="width: 100%">
<el-option
v-for="item in journalList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="Paper Title/SI Title" prop="paperTitle">
<el-input v-model="form.paperTitle" />
</el-form-item>
<el-form-item label="Paper /SI ID" prop="paperId">
<el-input v-model="form.paperId" />
</el-form-item>
<el-form-item label="Screenshot" prop="screenshot">
<PasteUpload v-model="form.screenshot" style="width: 100%" />
</el-form-item>
<el-form-item label="Remark" prop="remark">
<el-input
v-model="form.remark"
type="textarea"
:rows="3"
maxlength="200"
show-word-limit
autocomplete="off"
placeholder="富文本框,支持粘贴图片"
/>
</el-form-item>
<template v-if="form.reason === 'Other'">
<el-form-item label="Points Distribution" prop="points">
<el-input-number
v-model="form.points"
:min="0"
:max="100"
style="width: 180px"
/>
</el-form-item>
<el-form-item label="Voucher Distribution($)" prop="voucher">
<el-input-number
v-model="form.voucher"
:min="0"
:max="100"
style="width: 180px"
/>
</el-form-item>
</template>
<template v-else>
<el-form-item label="Rewards Distribution">
<el-select
v-model="form.rewardSelect"
placeholder="Select distribtuion"
style="width: 100%"
>
<el-option
v-for="item in rewardOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</template>
<div style="display: flex;justify-content: center;">
<el-button @click="emit('update:visible', false)">Cancel</el-button>
<el-button type="primary" @click="handleConfirm">Confirm</el-button>
</div>
</el-form>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, watch, computed } from "vue";
import PasteUpload from "@/views/promotePlus/components/PasteUpload/index.vue";
import { ElForm, ElMessage } from "element-plus";
const props = defineProps<{ visible: boolean; role: string }>();
const emit = defineEmits<{
(event: "update:visible", value: boolean): void;
(
event: "success",
payload: { email: string; points: number; voucher: number }
): void;
}>();
const innerVisible = ref(props.visible);
watch(
() => props.visible,
(v) => (innerVisible.value = v)
);
watch(innerVisible, (v) => emit("update:visible", v));
const sharingChannelsList = ["WeChat", "QQ", "Email", "Twitter", "Facebook"];
const sharingTypeList = ["Featured Papers", "Notification", "News", "Activity"];
const journalList = ["CMC", "BMC", "AMM"];
const rewardOptions = [
{ label: "20 Points + 20 Voucher", value: "20|20" },
{ label: "40 Points + 40 Voucher", value: "40|40" },
];
const formRef = ref<typeof ElForm | null>(null);
const form = reactive({
email: "",
name: "",
reason: "Behavior", // 默认选中Behavior of sharing
sharingChannels: "",
sharingType: "",
journal: "",
paperTitle: "",
paperId: "",
screenshot: "",
remark: "",
points: 0,
voucher: 0,
rewardSelect: "",
});
function resetForm() {
Object.assign(form, {
email: "",
name: "",
reason: "Behavior", // reset时默认Behavior
sharingChannels: "",
sharingType: "",
journal: "",
paperTitle: "",
paperId: "",
screenshot: "",
remark: "",
points: 0,
voucher: 0,
rewardSelect: "",
});
formRef.value?.clearValidate();
}
function handleReasonChange(val: string) {
// 清空与奖励相关内容和所有校验提示
form.points = 0;
form.voucher = 0;
form.rewardSelect = "";
formRef.value?.clearValidate(); // 切换 reason 时会自动清除所有表单的校验红框和错误提示
}
function autoFillByEmail() {
// 假数据逻辑(邮箱结尾相同的名字)
if (!form.email) return;
const map = {
"123@qq.com": {
name: "张三",
paperTitle: "深度学习方法研究",
paperId: "10001",
},
"test@qq.com": { name: "李四", paperTitle: "AI影响分析", paperId: "10002" },
"heweny@gmail.com": {
name: "Weney He",
paperTitle: "Bridging 2D and 3D Object Detection",
paperId: "56982",
},
};
const v = map[form.email];
if (v) {
form.name = v.name;
form.paperTitle = v.paperTitle;
form.paperId = v.paperId;
} else {
form.name = "";
form.paperTitle = "";
form.paperId = "";
}
}
const rules = computed(() => {
return {
email: [
{ required: true, message: "请输入邮箱", trigger: "blur" },
{ type: "email", message: "邮箱格式不正确", trigger: "blur" },
],
reason: [{ required: true, message: "请选择原因", trigger: "change" }],
sharingChannels:
form.reason === "Behavior"
? [{ required: true, message: "请选择渠道", trigger: "change" }]
: [{ required: false, message: "请选择渠道", trigger: "change" }],
sharingType:
form.reason === "Behavior"
? [{ required: true, message: "请选择类型", trigger: "change" }]
: [],
journal:
form.reason === "Behavior"
? [{ required: true, message: "请选择Journal", trigger: "change" }]
: [],
paperTitle:
form.reason === "Behavior"
? [{ required: true, message: "请输入标题", trigger: "blur" }]
: [],
paperId: form.reason === "Behavior"
? [{ required: true, message: "请输入", trigger: "blur" }]
: [],
screenshot:
form.reason === "Behavior"
? [{ required: true, message: "请上传截图", trigger: "change" }]
: [],
remark: form.reason === "Behavior"
? [{ required: true, message: "请输入", trigger: "blur" }]
: [],
rewardSelect:
form.reason === "Behavior"
? [{ required: true, message: "请选择奖励发放方式", trigger: "change" }]
: [],
points:
form.reason === "Other"
? [
{
validator: (rule: any, value: number, callback: any) => {
if (value < 0 || value > 100) callback("范围0-100");
else if (form.points === 0 && form.voucher === 0)
callback("至少有一项大于0");
else callback();
},
trigger: "change",
},
]
: [],
voucher:
form.reason === "Other"
? [
{
validator: (rule: any, value: number, callback: any) => {
if (value < 0 || value > 100) callback("范围0-100");
else if (form.points === 0 && form.voucher === 0)
callback("至少有一项大于0");
else callback();
},
trigger: "change",
},
]
: [],
};
});
function handleConfirm() {
formRef.value?.validate((valid) => {
if (!valid) return;
let send;
if (form.reason === "Other") {
send = { email: form.email, points: form.points, voucher: form.voucher };
} else {
const [p, v] = (form.rewardSelect || "").split("|");
send = { email: form.email, points: Number(p), voucher: Number(v) };
}
emit("success", send);
});
}
</script>
<style scoped lang="scss">
:deep(.upload-areas){
margin-bottom: 0!important;
}
:deep(.example-section){
top:-20px!important;
}
// 弹窗标题样式
.distribute-rewards-modal :deep(.el-dialog__header) {
background: #f9fafb;
margin: 0;
padding: 16px;
border-bottom: 1px solid #e5e7eb;
}
.distribute-rewards-modal :deep(.el-dialog__body) {
padding: 24px 24px 15px 24px;
}
</style>