問題背景
前端交互中經常使用確認框。在刪除、修改等操作時,調用后端接口之前,先跳出彈框顯示提示信息,提示用戶確認,避免用戶誤操作。
項目中全局引入了Element UI,提供了一套模態對話框組件,用於消息提示、確認消息、提交內容,使用起來也非常簡便。
(什么是“模態”?可將其理解為:特定條件觸發之后產生的)
以下來自於element官網文檔:
如果你完整引入了 Element,它會為
Vue.prototype
添加如下全局方法:$msgbox
,$alert
,$confirm
和$prompt
。因此在Vue instance
中可以采用本頁面中的方式調用 MessageBox。
代碼范例:
this.$confirm("此操作將永久刪除該文件, 是否繼續?", "提示", {
confirmButtonText: "確定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$message({ type: "success", message: "刪除成功!" });
})
.catch(() => {
this.$message({ type: "info", message: "已取消刪除" });
});
Element允許復寫樣式,如果全局都需要,則可以進行寫在全局自定義樣式單中,覆蓋掉原有樣式。
當Element提供的默認組件不能滿足需求時,需要思考一下如何實現?
實現嘗試
在單組件內部實現確認框
在組件內定義一個對話框,使用時將dialog顯示為可見,點擊確認時調用方法,點擊取消/關閉時將dialog設置為不可見。
在當前頁面只需要一個確認框的時候,dialog的標題、內容、確認時調用的方法(@click = "handler"
)都可以寫死。
- 怎么修改對話框內容?
當頁面上有多個不同方法均需要對話框確認,那么el-dialog對應的數據是變動的,使用v-model
指令綁定一個confirmDialog對象,在觸發對話框時,實時修改該對話框所顯示的內容,以及按鈕對應的方法。
<el-dialog width="600px" :title="confirmDialog.title" :visible.sync="confirmDialog.show">
<span>{{ confirmDialog.message }}</span>
<div slot="footer" class="dialog-footer">
<el-button @click="confirmDialog.show = false">
取 消
</el-button>
<el-button type="primary" @click="confirmDialog.handler">
確 定
</el-button>
</div>
</el-dialog>
<el-button @click = ""></el-button>
script中方法:
deleteFile() {
this.confirmDialog.title = "刪除";
this.confirmDialog.message = "確認刪除文件嗎?";
this.confirmDialog.handler = this.doDeleteFile;
this.confirmDialog.show = true;
},
doDeleteFile() {
// 刪除文件方法
}
- 公有部分抽取
在上述實現中,我們使用多個不同方法去操作同一對象,並且每個操作都需要兩個方法實現,第一個方法用來修改confirmDialog的值,第二個方法用來監聽確認按鈕的點擊事件,執行操作。
很容易得出,第一個方法是每個操作都類似的,可以復用的,彈窗HTML代碼和樣式代碼也是共用的,我們將公有的部分獨立成組件,就避免了重復工作。
如何抽取?
由上一節,我們容易得出,需要抽取的是確認框的DOM,樣式,以及數據對象。
為什么使用extend
上一章總結了子組件如何抽取,並介紹了在父組件中如何使用子組件,使用方法為:
在父組件中引入並注冊子組件,在父組件中傳入數據,為子組件的prop賦值,並在父組件中控制子組件的顯示。
使用父子組件 +局部注冊,無需關注子組件的創建,相對來說比較簡單。但是有時也會遇到問題:
- 子組件的模板都是事先定義好的,如果我要從接口動態渲染組件模板怎么辦?
- 子組件都是在父組件內定義好的位置渲染,假如想要在JS代碼中靈活調用,在任意地方渲染怎么辦?
這時就輪到Vue.extend()
出場了。
Vue.extend()
Vue.extend()
是 Vue
框架提供的全局api,查閱官網文檔,相關說明如下:
類比Java,可以將定義好的組件看成一個模板類,使用Vue.extend()生成該模板類的繼承子類。模板類中提供了默認的變量(模板、樣式、變量等),並定義了方法,在js代碼中可以繼承並覆蓋父類的變量和方法。Vue.extend()中接收的參數相當於子類的構造參數。
容易得出,我們需要傳入的是對話框綁定的數據模型(data),以及點擊確認后執行的方法。
- Promise
參考Element的做法,使用ES6
中的Promise
對象封裝構造函數的返回,能使代碼更加簡潔。
代碼實現
import Vue from 'vue';
import confirm from '../Comfirm.vue';
let confirmConstructor = Vue.extend(confirm);
let theConfirm = function (content) {
return new Promise((res, rej) => {
//promise封裝,ok執行resolve,no執行rejectlet
let confirmDom = new confirmConstructor({
el: document.createElement('div')
})
document.body.appendChild(confirmDom.$el); //new一個對象,然后插入body里面
confirmDom.content = content; //為了使confirm的擴展性更強,這個采用對象的方式傳入,所有的字段都可以根據需求自定義
confirmDom.ok = function () {
res()
confirmDom.isShow = false
}
confirmDom.close = function () {
rej()
confirmDom.isShow = false
}
})
}
export default theConfirm;
Confirm.vue
<template>
<!-- 自定義確認彈窗樣式 -->
<el-dialog width="600px" :title="content.title" :visible.sync="content.show" v-if="isShow">
<span>{{ content.message }}</span>
<div slot="footer" class="dialog-footer">
<el-button @click="close">
取 消
</el-button>
<el-button type="primary" @click="ok">
確 定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
data() {
return {
// 彈窗內容
isShow: true,
content: {
title: "",
message: "",
data: "",
show: false
}
};
},
methods: {
close() {
},
ok() {
}
}
};
</script>
<style>
</style>
在main.js中引入
import confirm from '@/confirm.js'
Vue.prototype.$confirm = confirm;
在任意方法中使用
this.$confirm({ title: "刪除", message: "確認刪除該文件嗎?", show: true })
.then(() => {
//用戶點擊確認后執行
})
.catch(() => {
// 取消或關閉
});
}
總結
本篇主要涉及知識點:
Vue.prototype
為Vue
實例添加方法Vue.extend()
的使用方法Promise
對象的定義和使用
面向對象的思想,可復用、易擴展、易維護,是我們編程過程中應當時刻注意的原則。