需求說明
- 彈窗中內嵌一個 form 表單
- 原始代碼
<script setup lang="ts">
import { reactive, ref } from "vue"
import type { FormRules } from 'element-plus'
const ruleFormRef = ref()
interface RuleForm {name: stringregion: number | null
}
const ruleForm = reactive<RuleForm>({name: '',region: null,
})
const rules = reactive<FormRules<RuleForm>>({name: [{ required: true, message: '請填寫姓名', trigger: 'blur' },],region: [{ required: true, message: '請選擇區域編碼', trigger: 'change' },]
})
const dialogVisible = ref(false);
function handelDialogPop(type: string) {if (type == "open") {dialogVisible.value = true; // 開啟彈窗} else if (type == "submit") {ruleFormRef.value.validate((valid: any, fields: any) => {if (valid) {console.log('提交成功')// 關閉彈窗ruleFormRef.value.resetFields();dialogVisible.value = false;} else {console.log('error submit!', fields)}})} else if (type == "cancel") {// 關閉彈窗ruleFormRef.value.resetFields();dialogVisible.value = false}
}
</script>
<template><div class="dataBox"><el-button type="primary" @click="handelDialogPop('open')">開啟彈窗</el-button><el-dialog v-model="dialogVisible" title="彈窗" width="500"><el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto"><el-form-item label="姓名" prop="name"><el-input v-model="ruleForm.name" /></el-form-item><el-form-item label="區域" prop="region"><el-select v-model="ruleForm.region" placeholder="區域編碼"><el-option label="第一區" :value="1" /><el-option label="第二區" :value="2" /></el-select></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button type="primary" plain @click="handelDialogPop('cancel')">取消</el-button><el-button type="primary" @click="handelDialogPop('submit')">提交</el-button></div></template></el-dialog></div>
</template>
- 點擊取消按鈕,或者提交通過校驗時,先執行了 form 表單的 resetFields 事件。此代碼會將表單的值重置為初始值,并且移除所有校驗。這樣可以保證下次點開彈窗時,不會保留上次操作 form 的痕跡。
- 為了省事兒,我把所有對 dialog 的操作都寫進了 handelDialogPop 函數里,傳入 type 來區分是什么事件(這里就是出問題的關鍵)
發現問題
-
手動點擊關閉按鈕,或者點擊 model 空白區域時,彈窗被關閉。未執行 form 表單的 resetFields 方法,所以再次打開時,彈窗保留了上次操作的痕跡(form 表單未重置)
-
因此需要監聽 dialog 的關閉事件,官方提供了一個方法,before-close
<el-dialog v-model="dialogVisible" title="彈窗" width="500" :before-close="handelDialogPop('cancel')">
...
- 問題出現了,一進入頁面時,直接拋錯。報錯信息可看出,before-close 被觸發了
問題解決
- 文檔中表明,before-close 傳參,done 說明會執行。
- 重新為 before-close 封裝一個函數
完整代碼
<script setup lang="ts">
import { reactive, ref } from "vue"
import type { FormRules } from 'element-plus'
const ruleFormRef = ref()
interface RuleForm {name: stringregion: number | null
}
const ruleForm = reactive<RuleForm>({name: '',region: null,
})
const rules = reactive<FormRules<RuleForm>>({name: [{ required: true, message: '請填寫姓名', trigger: 'blur' },],region: [{ required: true, message: '請選擇區域編碼', trigger: 'change' },]
})
const dialogVisible = ref(false);
function beforeCloseDialog() {console.log("執行了 beforeCloseDialog");ruleFormRef.value.resetFields();dialogVisible.value = false
}
function handelDialogPop(type: string) {if (type == "open") {dialogVisible.value = true} else if (type == "submit") {ruleFormRef.value.validate((valid: any, fields: any) => {if (valid) {console.log('提交成功')beforeCloseDialog();} else {console.log('error submit!', fields)}})} else if (type == "cancel") {// 關閉彈窗beforeCloseDialog()}
}
</script>
<template><div class="dataBox"><el-button type="primary" @click="handelDialogPop('open')">開啟彈窗</el-button><el-dialog v-model="dialogVisible" title="彈窗" width="500" :before-close="beforeCloseDialog"><el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto"><el-form-item label="姓名" prop="name"><el-input v-model="ruleForm.name" /></el-form-item><el-form-item label="區域" prop="region"><el-select v-model="ruleForm.region" placeholder="區域編碼"><el-option label="第一區" :value="1" /><el-option label="第二區" :value="2" /></el-select></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button type="primary" plain @click="handelDialogPop('cancel')">取消</el-button><el-button type="primary" @click="handelDialogPop('submit')">提交</el-button></div></template></el-dialog></div>
</template>