在使用elementUI的彈窗插件el-dialog時职抡,因為每次打開必須要重新渲染里面的內(nèi)容葬燎,所以使用了destroy-on-close
屬性,發(fā)現(xiàn)并沒有用:
<el-dialog :key="popupType" title="選擇用戶" :visible.sync="popupShow" :destroy-on-close="true">
<div>
彈窗內(nèi)容缚甩,這里省略一萬行谱净。。擅威。
</div>
</el-dialog>
F12打開控制臺壕探,發(fā)現(xiàn)加不加destroy-on-close屬性,關(guān)閉dialog郊丛,這段代碼都存在李请,而不是消失。
具體原因可以參考以下這個文章:http://www.reibang.com/p/77d1ba476a6d厉熟,重點看下作者介紹的原理即可导盅。
但文章里說的把el-dialog標(biāo)簽寫在父組件不寫在子組件就也可以讓destroy-on-close生效,但實際測試過程中發(fā)現(xiàn)這種寫法還是無法讓元素消失揍瑟,打開F12還是有元素存在白翻,不是我們想要的效果。
經(jīng)過測試發(fā)現(xiàn)绢片,把el-dialog標(biāo)簽寫在父組件不寫在子組件再使用destroy-on-close屬性滤馍,實際它只能初始化dialog組件內(nèi)部包裹的子組件data數(shù)據(jù)!杉畜!而且子組件的生命周期函數(shù)鉤子會在關(guān)閉彈窗后還會執(zhí)行一次<脱选!此叠,這樣就感覺destroy-on-close很雞肋纯续。随珠。。因為如果你只是想讓表單數(shù)據(jù)重置猬错,那么這其實相當(dāng)于你在關(guān)閉彈窗的事件寫上element表單重置的resetFields()窗看,但如果想要清空數(shù)據(jù),初始化也可能不是你想要的清空效果(這里注意:重置不等于清空倦炒,重置的是初始化傳入的數(shù)據(jù)显沈,清空是把數(shù)據(jù)全部置空),可以接著看下下面的小tip:
小Tip:resetFields()無效的辦法
如果你是新增和編輯的復(fù)用彈窗的情況逢唤,你想讓打開的彈窗表單數(shù)據(jù)重置拉讯,尤其是想要清空表單數(shù)據(jù),當(dāng)你在關(guān)閉彈窗的使用resetFields()鳖藕,你點擊編輯在打開彈窗的時候把數(shù)據(jù)傳入魔慷,再點擊新增,那么這時候就新增彈窗內(nèi)還是會顯示之前編輯時的數(shù)據(jù)著恩,感覺resetFields好像不生效院尔,實際正確使用方法應(yīng)該是先讓彈窗打開this.dialogShow = true
再使用this.$nextTick
把數(shù)據(jù)傳入,讓數(shù)據(jù)傳入比內(nèi)置的初始化數(shù)據(jù)慢一步喉誊,這樣初始化數(shù)據(jù)默認就不是你傳入的數(shù)據(jù)邀摆。有寫過一篇更詳細的文章,有此類問題的朋友可以參考:http://www.reibang.com/p/038580ebf33f
這里提供一份我在線環(huán)境測試的各種表單重置數(shù)據(jù)不會有問題的el-dialog寫法demo伍茄,可以直接線上調(diào)試:
線上調(diào)試測試地址:https://codesandbox.io/s/wispy-meadow-yn4yz
一栋盹、如果想要把el-dialog標(biāo)簽都寫在父組件或者把el-dialog標(biāo)簽整個作為子組件,重置表單(清空)需要配合使用this.$refs.form.resetFields()
和this.$nextTick(()=>{})
1幻林、下面是el-dialog標(biāo)簽都寫在父組件的使用:
// 父組件
<template>
<div id="app">
<el-button type="success" @click="handelOpen('add')">新增</el-button>
<el-button @click="handelOpen('edit')">編輯</el-button>
<el-dialog
:title="'彈窗測試-' + (dialogType === 'add' ? '新增' : '編輯')"
:visible.sync="dialogVisible"
:before-close="handleClose"
>
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="活動名稱" prop="name">
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose2">取 消</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
dialogVisible: false,
dialogType: "", //彈窗類型
form: {
name: "",
},
};
},
methods: {
handelOpen(val) {
this.dialogVisible = true;
this.dialogType = val;
if (val === "edit") {
// 模擬數(shù)據(jù)請求
setTimeout(() => {
// this.$nextTick讓空數(shù)據(jù)初始化后再傳入贞盯,避免傳入的數(shù)據(jù)直接變成初始化數(shù)據(jù),導(dǎo)致無法重置(清空數(shù)據(jù))
this.$nextTick(() => {
this.form = {
name: "阿布",
};
});
}, 500);
}
},
// 重置表單
handleReset() {
this.$refs.form.resetFields();
},
// 關(guān)閉彈窗并重置表單
handleClose2() {
this.handleReset();
this.dialogVisible = false;
},
},
};
</script>
2沪饺、下面是el-dialog標(biāo)簽整個作為子組件的使用:
// 父組件
<template>
<div id="app">
<el-button type="success" @click="handelOpen('add')">新增</el-button>
<el-button @click="handelOpen('edit')">編輯</el-button>
<test
v-model="dialogVisible"
:title="'彈窗測試-' + (dialogType === 'add' ? '新增' : '編輯')"
:form="form"
@closeDialog="handleClose"
/>
</div>
</template>
<script>
import test from "./components/test.vue";
export default {
name: "App",
components: {
test,
},
data() {
return {
dialogVisible: false,
dialogType: "", //彈窗類型
form: {
name: "",
},
};
},
methods: {
handelOpen(val) {
this.dialogVisible = true;
this.dialogType = val;
if (val === "edit") {
// 模擬數(shù)據(jù)請求
setTimeout(() => {
// this.$nextTick讓空數(shù)據(jù)初始化后再傳入躏敢,避免傳入的數(shù)據(jù)直接變成初始化數(shù)據(jù),導(dǎo)致無法重置(清空數(shù)據(jù))
this.$nextTick(() => {
this.form = {
name: "阿布",
};
});
}, 500);
}
},
// 關(guān)閉彈窗并重置表單
handleClose() {
this.dialogVisible = false;
},
},
};
</script>
但是注意不管是哪種方式整葡,如若需要清空表單數(shù)據(jù)件余,test組件傳入的表單數(shù)據(jù)form都需要監(jiān)聽并用另一個變量info接收并進行深拷貝,內(nèi)外數(shù)據(jù)才不會相互影響
// src/components/test.vue 子組件
<template>
<div>
<el-dialog
:title="title"
:visible.sync="dialogVisible"
:before-close="handleClose"
>
<el-form ref="form" :model="info" label-width="80px">
<el-form-item label="活動名稱" prop="name">
<el-input v-model="info.name"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "test",
props: {
value: {
type: Boolean,
default: false,
},
title: {
type: String,
default: "",
},
form: {
type: Object,
default: () => ({}),
},
},
computed: {
dialogVisible: {
// 利用計算屬性動態(tài)設(shè)置外部v-model綁定值
set(val) {
this.$emit("input", val);
},
// 利用計算屬性動態(tài)獲取外部v-model綁定值
get() {
return this.value;
},
},
},
watch: {
form(newVal, oldVal) {
console.log("newVal", newVal);
// 深拷貝
this.info = JSON.parse(JSON.stringify(newVal));
},
},
data() {
return {
info: {},
};
},
methods: {
handleReset() {
// 重置
this.$refs.form.resetFields();
},
handleClose() {
// 重置
this.handleReset();
// 關(guān)閉彈窗
this.$emit("closeDialog");
},
},
};
</script>
二遭居、如果想要把el-dialog標(biāo)簽寫在父組件啼器,內(nèi)容寫在子組件,更好的替代方案:用v-if或者key來實現(xiàn)俱萍,解決以上一切問題端壳!
1、下面是key的使用(test為子組件):
<template>
<div id="app">
<el-button type="success" @click="handelOpen('add')">新增</el-button>
<el-button @click="handelOpen('edit')">編輯</el-button>
<!-- 可以充當(dāng)resetFields重置表單的方法來使用 -->
<!-- 需要注意的是 key綁定的dialogVisible每次開啟和關(guān)閉變化都會讓test子組件生命周期重新加載和data數(shù)據(jù)初始化-->
<!-- test組件傳入的表單數(shù)據(jù)都需要監(jiān)聽并用另一個變量接收枪蘑,且不能初始化就觸發(fā)監(jiān)聽 -->
<el-dialog
:title="'彈窗測試-' + (dialogType === 'add' ? '新增' : '編輯')"
:visible.sync="dialogVisible"
:before-close="handleClose"
>
<test :key="dialogVisible" :form="form" @closeDialog="handleClose" />
</el-dialog>
</div>
</template>
<script>
import test from "./components/test.vue";
export default {
name: "App",
components: {
test,
},
data() {
return {
dialogVisible: false,
dialogType: "", //彈窗類型
form: {
name: "",
},
};
},
methods: {
handelOpen(val) {
this.dialogVisible = true;
this.dialogType = val;
if (val === "edit") {
// 模擬數(shù)據(jù)請求
setTimeout(() => {
this.form = {
name: "阿布",
};
}, 500);
}
},
// 關(guān)閉彈窗
handleClose() {
this.dialogVisible = false;
},
},
};
</script>
2损谦、下面是v-if的使用(test為子組件):
<template>
<div id="app">
<el-button type="success" @click="handelOpen('add')">新增</el-button>
<el-button @click="handelOpen('edit')">編輯</el-button>
<!-- 可以充當(dāng)resetFields重置表單的方法來使用 -->
<!-- 需要注意的是 v-if綁定的dialogVisible每次關(guān)閉會讓test子組件生命周期重新加載和data數(shù)據(jù)初始化-->
<!-- test組件傳入的表單數(shù)據(jù)都需要監(jiān)聽并用另一個變量接收岖免,且不能初始化就觸發(fā)監(jiān)聽 -->
<el-dialog
:title="'彈窗測試4-' + (dialogType === 'add' ? '新增' : '編輯')"
:visible.sync="dialogVisible"
:before-close="handleClose"
>
<test v-if="dialogVisible" :form="form" @closeDialog="handleClose" />
</el-dialog>
</div>
</template>
<script>
import test from "./components/test.vue";
export default {
name: "App",
components: {
test,
},
data() {
return {
dialogVisible: false,
dialogType: "", //彈窗類型
form: {
name: "",
},
};
},
methods: {
handelOpen(val) {
this.dialogVisible = true;
this.dialogType = val;
if (val === "edit") {
// 模擬數(shù)據(jù)請求
setTimeout(() => {
this.form = {
name: "阿布",
};
}, 500);
}
},
// 關(guān)閉彈窗
handleClose() {
this.dialogVisible = false;
},
},
};
</script>
以上效果等同于使用 destroy-on-close,但不推薦使用 destroy-on-close:
3照捡、下面是destroy-on-close的使用颅湘,不推薦(test為子組件):
<template>
<div id="app">
<el-button type="success" @click="handelOpen('add')">新增</el-button>
<el-button @click="handelOpen('edit')">編輯</el-button>
<!-- 這種方法destroy-on-close可以生效-->
<!-- 可以充當(dāng)resetFields重置表單的方法來使用 -->
<!-- 需要注意的是 destroy-on-close 只會在每次關(guān)閉會讓test子組件生命周期重新加載和data數(shù)據(jù)初始化,但元素不會去除-->
<!-- test組件傳入的表單數(shù)據(jù)都需要監(jiān)聽并用另一個變量接收栗精,且不能初始化就觸發(fā)監(jiān)聽 -->
<el-dialog
:title="'彈窗測試3-' + (dialogType === 'add' ? '新增' : '編輯')"
destroy-on-close
:visible.sync="dialogVisible"
:before-close="handleClose"
>
<test :form="form" @closeDialog="handleClose" />
</el-dialog>
</div>
</template>
<script>
import test from "./components/test.vue";
export default {
name: "App",
components: {
test,
},
data() {
return {
dialogVisible: false,
dialogType: "", //彈窗類型
form: {
name: "",
},
};
},
methods: {
handelOpen(val) {
this.dialogVisible = true;
this.dialogType = val;
if (val === "edit") {
// 模擬數(shù)據(jù)請求
setTimeout(() => {
this.form = {
name: "阿布",
};
}, 500);
}
},
// 關(guān)閉彈窗
handleClose() {
this.dialogVisible = false;
},
},
};
</script>
但是注意不管是v-if或者key或者destroy-on-close哪種方式闯参,如若需要清空表單數(shù)據(jù),test組件傳入的表單數(shù)據(jù)form都需要監(jiān)聽并用另一個變量info接收并進行深拷貝悲立,內(nèi)外數(shù)據(jù)才不會相互影響鹿寨,且不能初始化watch就使用immediate:true
就觸發(fā)監(jiān)聽,才能清空數(shù)據(jù):
// src/components/test.vue 子組件
<template>
<div>
<el-form ref="form" :model="info" label-width="80px">
<el-form-item label="活動名稱" prop="name">
<el-input v-model="info.name"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
</span>
</div>
</template>
<script>
export default {
name: "test",
props: {
form: {
type: Object,
default: () => ({}),
},
},
data() {
return {
info: {},
};
},
watch: {
form(newVal, oldVal) {
console.log("newVal", newVal);
// 深拷貝
this.info = JSON.parse(JSON.stringify(newVal));
},
},
created() {
console.log("created");
},
mounted() {
console.log("mounted");
},
methods: {
handleClose() {
// 關(guān)閉彈窗
this.$emit("closeDialog");
},
},
};
</script>
這樣的話级历,既重新渲染了释移,又保證了動畫會執(zhí)行叭披,所有情況都歸納出來了寥殖,解決了每次彈窗不同寫法無法重新渲染(更多是想要清空數(shù)據(jù))問題的懵逼和尷尬,完美涩蜘。嚼贡。