# "可插拔式"组件设计,领略组件开发的奥秘
从一个 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 库,方便大家学习和使用,
欢迎关注公众号「前端进阶课」认真学前端,一起进阶。
# "可插拔式"组件设计,领略组件开发的奥秘的更多相关文章
- xmlplus 组件设计系列之零 - xmlplus 简介
xmlplus 是什么 xmlplus 是博主写的一个 JavaScript 框架,用于快速开发前后端项目. xmlplus 基于组件设计,组件是基本的构造块.评价组件设计好坏的一个重要标准是封装度. ...
- admin源码解析以及仿照admin设计stark组件
---恢复内容开始--- admin源码解析 一 启动:每个APP下的apps.py文件中. 首先执行每个APP下的admin.py 文件. def autodiscover(): autodisco ...
- Vue 组件设计
Vue 组件设计 Vue 作为 MVVM 框架一员,不管是写业务还是基础服务,都少不了书写组件.本文总结一下书写业务组件的一些心得. 为什么要写组件? 我们知道,只要是组件,就需要在引用的时候与 vi ...
- 企业 SOA 设计(2)–组件化产品开发平台
上一篇<企业 SOA 设计(1)–ESB 设计>中,写到我们的 SOA 设计分为两个层面来进行:一个是系统间的 SOA 设计,主要通过 ESB 来完成:另一方面则是单个应用系统内部的 SO ...
- HT图形组件设计之道(四)
在<HT图形组件设计之道(二)>我们展示了HT在2D图形矢量的数据绑定功能,这种机制不仅可用于2D图形,HT的通用组件甚至3D引擎都具备这种数据绑定机制,此篇我们将构建一个3D飞机模型,展 ...
- HT图形组件设计之道(三)
上篇我们通过定制了CPU和内存展示界面,体验了HT for Web通过定义矢量实现图形绘制与业务数据的代码解耦及绑定联动,这类案例后续文章还会继续以便大家掌握更多的矢量应用场景,本篇我们先切换个话题, ...
- 如何优雅的设计 React 组件
作者:晓冬 本文原创,转载请注明作者及出处 如今的 Web 前端已被 React.Vue 和 Angular 三分天下,一统江山十几年的 jQuery 显然已经很难满足现在的开发模式.那么,为什么大家 ...
- 如何优雅的设计React组件
如何优雅的设计 React 组件 如今的 web 前端已被 React.Vue 和 Angular 三分天下,一统江山十几年的 jQuery 显然已经很难满足现在的开发模式.那么,为什么大家会觉得 j ...
- React组件设计
React组件设计 组件分类 展示组件和容器组件 展示组件 容器组件 关注事物的展示 关注事物如何工作 可能包含展示和容器组件,并且一般会有DOM标签和css样式 可能包含展示和容器组件,并且不会有D ...
- React组件设计(转)
React组件设计 组件分类 展示组件和容器组件 展示组件 容器组件 关注事物的展示 关注事物如何工作 可能包含展示和容器组件,并且一般会有DOM标签和css样式 可能包含展示和容器组件,并且不会有D ...
随机推荐
- Open Source Software List: The Ultimate List
http://www.datamation.com/open-source/ Accessibility 1. The Accessibility Project The Business Value ...
- SuperSocket进程级别隔离
在 SuperSocket 1.5 中, 我们增加了 AppDomain 级别隔离的功能,让你可以运行多个服务器实例在相互独立的 AppDomain 上. 此功能提供了较高级别的安全性和资源的隔离,并 ...
- angular input框点击别处 变成不可输入状态
<input type="text" ng-model="edit" ng-disabled="!editable" focus-me ...
- linux包之nmap之ncat命令
[root@ka1che225 ~]# which nc/usr/bin/nc[root@ka1che225 ~]# which ncat/usr/bin/ncat[root@ka1che225 ~] ...
- H3C 配置CHAP验证
- Codeforces Round #180 (Div. 1 + Div. 2)
A. Snow Footprints 如果只有L或者只有R,那么起点和终点都在边界上,否则在两者的边界. B. Sail 每次根据移动后的曼哈顿距离来判断是否移动. C. Parity Game 如果 ...
- H3C NAT ALG
- Redis - 命令行工具
使用Redis内置的命令行工具 redis-cli一些便捷的命令: 1.执行单条命令 平时在访问 Redis 服务器,一般都会使用 redis-cli 进入交互模式,然后一问一答来读写服务器,这种情况 ...
- 【33.18%】【hdu 5877】Weak Pair (3种解法)
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Total Submissi ...
- 手机网页H5 自适应不同分辨率的屏幕 必学标签meta之viewport
viewport 语法介绍 <meta name="viewport"content=" height = [pixel_value | device-height ...