# "可插拔式"元件設計,領略元件開發的奧祕
從一個 Confirm
元件開始,一步步寫一個可插拔式的元件。
處理一個正常的支付流程(比如支付寶購買基金)
- 點選購買按鈕
- 如果風險等級不匹配則:彈確認框(Confirm)
- 使用者確認風險後:彈出支付方式選擇彈窗(Dialog)
- 選擇好支付方式後:彈窗呼叫指紋驗證(Dialog)
- 如果關閉指紋驗證:提示是否輸入密碼(Dialog)
- 彈出輸入密碼的鍵盤(自定義鍵盤)
- 當然還有密碼加班
- 如果密碼輸入錯誤則彈出修改/重試提示(Confirm)
- ...再次彈出鍵盤
大約6個彈窗...
地攤貨(精簡版)
首先嚐試以一個平常的註冊元件實現
Confirm
通過 v-model="isShow"
切換展示,通過 @onConfirm
onCancel
接收點選事件。
元件程式碼
<template> <div v-if="value"> <slot></slot> <div> <div @click="cancelHandler">{{cancelTxt}}</div> <div @click="confirmHandler">{{confirmTxt}}</div> </div> </div> </template> <script> export default { props: { value: { type: Boolean, default: false, } }, data() { return { content: '', confirmTxt: '', cancelTxt: '', } }, methods: { close() { this.$emit('input'); }, cancelHandler() { this.$emit('onCancel'); }, confirmHandler() { this.$emit('onConfirm'); } } } </script>
使用程式碼
<confirm
v-model="isConfirmShow"
@onCancel="onCancel"
@onConfirm="onConfirm"
>內容部分</confirm>
那麼用它來完成上面的需求吧。
openRiskConfirm() { this.isRiskConfirmShow = true; }, onRiskCancel() { this.isRiskConfirmShow = false; }, onRiskConfirm() { // something this.openPaymeList(); }, openPaymeList() { this.isPaymentListShow = ture; } // ... 巴拉巴拉 // ... 大約需要 3*6 = 18 個方法才能完成需求(其他請求類的還不算)
如果你能接受,但是:
那麼萬一監管放鬆了,不需要校驗風險了呢?或者一開始沒有校驗風險,監管突然要校驗風險了呢?又或者不在 app
上使用,不用呼叫指紋呢?又或者要新增一個 人臉識別功能了呢?
程式碼改起來會是一個災難,因為就算業務程式碼是你寫的,你一段時間後也不一定能記得流程,而且,程式碼看起來沒有任何的連續性,只能一個個方法看。
流行款(精簡版)
針對上面的業務流程,嘗試使用現在比較流行的的彈窗。
元件:更改接收方法位置,從 props
放到 $data
中
<template>
<div>
<div>{{content}}</div>
<div>
<div @click="cancelHandler">{{cancelTxt}}</div>
<div @click="confirmHandler">{{confirmTxt}}</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
content: '',
confirmTxt: '',
cancelTxt: '',
onConfirm: function() {},
onCancel: function() {},
}
},
methods: {
uninstall() {
this.$destroy(true);
this.$el.parentNode.removeChild(this.$el);
},
cancelHandler() {
(typeof this.onCancel === 'function') && this.onCancel()
this.uninstall();
},
confirmHandler() {
(typeof this.onConfirm === 'function') && this.onConfirm()
this.uninstall();
}
}
}
</script>
註冊到全域性
import confirm from './confirm.vue'
export default {
install: function(Vue) {
const Profile = Vue.extend(confirm);
const PortfolioMsg = (options) => {
let $ele = document.createElement("div");
document.body.appendChild($ele);
new Profile({
data() {
return options;
}
}).$mount($ele);
};
Vue.prototype.$confirm = PortfolioMsg;
}
}
呼叫
this.$confirm({
content: '內容',
confirmTxt: '確定',
cancelTxt: '取消',
onConfirm: () => {
console.log('確定')
},
onCancel: () => {
console.log('取消')
}
})
哪啊麼用它完成上面的需求會如何?
this.$confirm({
content: '風險認證',
cancelTxt: '再看看',
confirmTxt: '同意',
onConfirm: () => {
// something
this.$dialog({
content: '指紋認證',
slot: `<div>指紋認證</div>`,
onFinish: () => {
// 支付 成功? 失敗?
// something
},
onCancel: () => {
// something
this.$confirm({
content: '密碼認證',
cancelTxt: '取消',
confirmTxt: '確定',
onConfirm: () => {
// something
this.$keyboard({
// 略
onFinish: (password) => {
// 密碼加密
// something
if (/* 密碼錯誤? */) {
// 重複了
// 這個程式碼就可以抽象成一個方法
this.$confirm({
content: '密碼認證',
cancelTxt: '取消',
confirmTxt: '確定',
// 略
})
}
}
})
},
onCancel: () => {
// 取消
}
})
}
})
},
onCancel: () => {
// 取消
}
})
這樣看起來確實清晰了很多,程式碼量也少了很多,不需要註冊全域性的元件可以通過在 methods
中封裝一個方法實現,維護起來也方便了很多。但是:回撥地獄有木有?也只是稍微輕鬆一點,可不可以再優化一下呢?
抽象版
ajax 的回撥地獄是通過 Promise
實現的,那麼上面的元件回撥地獄是不是也可以通過 Promise
實現呢?
import confirm from './confirm.vue'
export default {
install: function(Vue) {
const Profile = Vue.extend(confirm);
const PortfolioMsg = (options) => {
let $ele = document.createElement("div");
document.body.appendChild($ele);
const profile = new Profile({
data() {
return options;
}
}).$mount($ele);
return new Promise((resolve, reject) => {
profile.$on('onConfirm', resolve)
profile.$on('onCancel', reject)
})
};
Vue.prototype.$confirm = PortfolioMsg;
}
}
使用一下
this.$confirm({
confirmTxt: '確定'
}).then(res => {
console.log('點選了確定')
}).catch(res => {
console.log('點選了取消')
})
那麼回撥地獄的問題很輕鬆的就解決了,可讀性很高,中間新增刪除邏輯也變的特別方便,維護起來成本大大的降低了。具體程式碼自己抽象一遍或許更好哦。
大家其他的封裝方法嗎?請留言哈
最後
譯者寫了一個 React + Hooks 的 UI 庫,方便大家學習和使用,
React + Hooks 專案實戰
歡迎關注公眾號「前端進階課」認真學前端,一起進階。
相關推薦
# "可插拔式"元件設計,領略元件開發的奧祕
從一個 Confirm 元件開始,一步步寫一個可插拔式的元件。 處理一個正常的支付流程(比如支付寶購買基金) 點選購買按鈕 如果風險等級不匹配則:彈確認框(Confirm) 使用者確認風險後:彈出支付方式選擇彈窗(Dialog) 選擇好支付方式後:彈窗呼叫指紋驗證(Dialog) 如果關閉指紋驗證:提示是否
CMDB 資產采集——插件可插拔式、可拓展思想
資產采集 pat eve nbsp sel one ddp pre ram 功能描述 每個資產采集的插件都是一個獨立的py腳本統一放在一個目錄下,所有插件的路徑統一配置在settings.py 配置文件中,以字典形式配置。通過for 循環字典中插件逐個執行插件采集數據。增
Spring Boot +Spring AOP 可插拔式日誌思路
Spring 基於IOC容器管理Bean的方式,使得其有能力對IOC容器中的所有Bean進行無限可能的操作,Spring AOP是基於 IOC容器的高階特性,藉助與AOP能實現一些可插拔模組,而不影響原有系統的設計. 本節結合Spring Bo
帶你手寫基於 Spring 的可插拔式 RPC 框架(一)介紹
目錄: 帶你手寫基於 Spring 的可插拔式 RPC 框架(一)介紹 帶你手寫基於 Spring 的可插拔式 RPC 框架(二)整體結構 帶你手寫基於 Spring 的可插拔式 RPC 框架(三)通訊協議模組 帶你手寫基於 Spring 的可插拔式 RPC 框架(四)代理類的注入與服務啟動 帶你手寫基於 S
可熱插拔式記憶體和cpu設計思路
需要一個單獨的註冊中心,cpu和記憶體在註冊中心註冊,並定時向註冊中心傳送心跳資料, 當註冊中心接收不到心跳資料時預設cpu或記憶體損壞,自動將任務分流到其他節點。 待更換後心跳恢復,註冊中心自動發現相應裝置,把任務分發到該節點。優點:實現了自動控制。缺點:對單獨註冊中心的要求較高,且存在單點故障,做不到高可
基於AppDomain的"插件式"開發
file 添加 ice rar ssl lib ria exec getname 很多時候,我們都想使用(開發)USB式(熱插拔)的應用,例如,開發一個WinForm應用,並且這個WinForm應用能允許開發人員定制擴展插件,又例如,我們可能維護著一個WinServic
我心中的核心元件(可插拔的AOP)~第二回 快取攔截器
回到目錄 AOP面向切面的程式設計,也稱面向方面的程式設計,我更青睞於前面的叫法,將一個大系統切成多個獨立的部分,而這個獨立的部分又可以方便的插拔在其它領域的系統之中,這種程式設計的方式我們叫它面向切面,而這些獨立的部分,我們很早之前叫它部件,在SOA裡,它叫做服務,而我認為叫它模組更加貼切,確實,這些與領
基於 Netty 的可插拔業務通訊協議的實現「2」特定業務訊息物件的設計
本文為該系列的第二篇文章,設計需求為:服務端程式和眾多客戶端程式通過 TCP 協議進行通訊,通訊雙方需通訊的訊息種類眾多。上一篇文章詳細描述了該通訊協議的二進位制資料幀格式以及基本 Java 訊息類,假設通訊雙方「服務端、客戶端」均由 Netty 框架構建而成,
PAM - 可插拔認證模塊
用戶名 掃描 權限 nor 規則 安全 6.2 htm ip地址 1、為什麽要使用PAM 為了讓用戶更合理地使用系統,應用程序或服務(如sshd、login、su、password、ftp等)不可避免地需要對用戶進行安全認證,若按照各自的規則去配置非常耗費時間和精力且不能重
如何連接oracle 12c可插拔數據庫
byte pdb start targe 執行 creat get 數據 contain 啟動根容器:[oracle@eric ~]$ export ORACLE_SID=cup[oracle@eric ~]$ sqlplus / as sysdbaSQL*Plus: Re
oracle 12c創建可插拔數據庫(PDB)及用戶
因此 shutdown 多少 lob from 如果 name 有用 大小寫 由於oracle 12c使用了CDB-PDB架構,類似於docker,在container-db內可以加載多個pluggable-db,因此安裝後需要額外配置才能使用。 一、修改listene
Oracle12c中多宿主容器數據庫(CDBs)和可插拔數據庫(PDBs)新特性之運行腳本
error local app tab OS ecif lora cron lis 對開發者和DBA們來說,對shell腳本批量任務的影響成了多宿主選項帶來的最大改變之一。因為多宿主環境通過服務來連接到可插拔數據庫,因此,依靠CRON和OS認證成了換成多宿主環境後的一
詳談Oracle12c新特點容器數據庫&可插拔數據庫(CDB&PDB)
數據 shared 臨時文件 time body pdb$seed uwp end 移除 一般信息 數據字典 CDB_FILE$ DBA_PDBS PDB$SEED
Oracle 12c 資料庫可插拔體系結構
在Oracle 12c資料庫中,可插拔資料庫擁有一些重要的結構,這些結構和非CDB資料庫的結構不同。 下面是一些要點: CDB:Container Database PDB:Pluggable D
使用Mixin技術拓展類定義,實現python類功能的可插拔
Q:我們有一些十分有用的方法,希望用它來拓展其他類的方法,但是需要新增方法的這些類之間並不一定屬於繼承關係。因此,沒有辦法將這些方法直接關聯到一個共同的基類上。 為了解決這個問題,我們可以使用Mixin技術,有兩個實現方法,一個是多重繼承,一個是類裝飾器。
第二篇 基於.net搭建熱插拔式web框架(沙箱的構建)
/// <summary>沙箱管道 /// </summary> public class SandBoxChannel : MarshalByRefObject { /// <summary>沙箱內載入的程式集
第三篇 基於.net搭建熱插拔式web框架(重造Controller)
public class HuberController { public dynamic ViewBag = new DynamicViewBag(); public ViewDataDictionary ViewData = new ViewDataD
基於.net搭建熱插拔式web框架(實現原理)
第一節:我們為什麼需要一個熱插拔式的web框架? 模組之間獨立開發 假設我們要做一個後臺管理系統,其中包括“使用者活躍度”、“產品管理”、"賬單管理"等模組。每個模組中有自己的業務特性,這些模組都與具體業務高度耦合,很難由一個團隊開發完所有模組。這樣看來,由資料事業部的同事來開發“使用者活躍度”模
第四篇 基於.net搭建熱插拔式web框架(RazorEngine實現)
/// <summary>頁面幫助類 /// A simple helper demonstrating the @Html.Raw /// </summary> /// <typeparam name="T"></typeparam
第五篇 基於.net搭建熱插拔式web框架(攔截器---請求管道)
好了,前邊我們把核心內容介紹完了,接下來要做的就是攔截使用者的請求,並把請求轉向沙箱內。 這裡我們準備通過實現一個HttpModule類來完成請求的攔截與轉發。新建一個HuberHttpModule類,並繼承IHttpModule。下面我們暫時只處理Application_BeginRequest事