从一个 Confirm
组件开始,一步步写一个可插拔式的组件。
处理一个正常的支付流程(比如支付宝购买基金)
- 点击购买按钮
- 如果风险等级不匹配则:弹确认框(Confirm)
- 用户确认风险后:弹出支付方式选择弹窗(Dialog)
- 选择好支付方式后:弹窗调用指纹验证(Dialog)
- 如果关闭指纹验证:提示是否输入密码(Dialog)
- 弹出输入密码的键盘(自定义键盘)
- 当然还有密码加班
- 如果密码输入错误则弹出修改/重试提示(Confirm)
- ...再次弹出键盘
大约6个弹窗...
地摊货(精简版)
首先尝试以一个平常的注册组件实现
Confirm
通过 v-model="isShow"
切换展示,通过 @onConfirm
和 onCancel
接收点击事件。
组件代码
{{cancelTxt}}
{{confirmTxt}}
使用代码
内容部分
那么用它来完成上面的需求吧。
openRiskConfirm() {
this.isRiskConfirmShow = true;
},
onRiskCancel() {
this.isRiskConfirmShow = false;
},
onRiskConfirm() {
// something
this.openPaymeList();
},
openPaymeList() {
this.isPaymentListShow = ture;
}
// ... 巴拉巴拉
// ... 大约需要 3*6 = 18 个方法才能完成需求(其他请求类的还不算)
如果你能接受,但是:
那么万一监管放松了,不需要校验风险了呢?或者一开始没有校验风险,监管突然要校验风险了呢?又或者不在 app
上使用,不用调用指纹呢?又或者要添加一个 人脸识别功能了呢?
代码改起来会是一个灾难,因为就算业务代码是你写的,你一段时间后也不一定能记得流程,而且,代码看起来没有任何的连续性,只能一个个方法看。
流行款(精简版)
针对上面的业务流程,尝试使用现在比较流行的的弹窗。
组件:更改接收方法位置,从 props
放到 $data
中
{{content}}
{{cancelTxt}}
{{confirmTxt}}
注册到全局
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: `指纹认证`,
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 项目实战
欢迎关注公众号「前端进阶课」认真学前端,一起进阶。