一直以来许多比较旧的弹窗方案,都是通过一个boolean值来控制显示与隐藏的,但是随着业务的深入,普通的弹窗方案对于业务的拓展已经不太适用了。自从React推出hooks后,社区也出了许多弹窗方案,其实我比较喜欢的就是eBay的nice-modal-react,我将基于它的思想,来进行改造。
1. 思路
社区中常用的做法是使用context方案来做对应的全局弹窗的渲染,如下所示:
children 取决于你弹窗的范围,如果是全局弹窗的话,那么 children 一般指的是 根组件。 ModalRenderComp 则代表实际需要渲染的弹窗。思路有了,接下来就围绕着这个思想来进行实现。
2. 先泼个冷水
注意我们的标题是,在Taro中设计弹窗,众所周知,Taro的app.js文件,是不会渲染其他内容的,咱先看看官网是怎么说的:
在实际的测试中,我发现只有H5的入口文件是支持渲染的,编译成小程序则不行。如果你的场景只有H5的话,那么这套全局弹窗的方案完全适用。如果是要做跨端的方案的话,比如同时兼容H5与小程序,那么是做不了全局的。我们只能把粒度范围缩小到页面中,也就是每个页面都需要引入一个Provider。
3. API 设计
一张图直观的展示API的用法,如图所示:
其中 useDialog 是需要实现的 hooks,TestModal 则是自定义的弹窗组件,InitData其实是用来约束弹窗的初始值类型的。show方法负责调用并返回一个Promise
4. 源码实现
在讲源码的时候,我也只会讲个大体的思路,具体实现的细节,可以看我在文章最后贴出来的代码地址。思路是最重要的,有了思路后,你可以对其进行各种各样的修改。
1. 渲染的弹窗
在第一点我们提到,ModalRenderComp 是实际需要渲染的弹窗组件(数组)。那么它是通过什么来进行渲染的,答案就是 context上的 modals,我们通过对modals进行相关的操作后,得出最后需要进行渲染的弹窗即可。
上图我通过加入了type,来区分弹窗的类型,simple类型代表简易的弹窗,后面会提到。custom则是自定义弹窗,我会根据这两个类型类做对应的ui组件渲染。当然这不是先要关心的点。我们需要关注的是,context中的 modals, 我们通过useReducer来做操作,通过dispatch不同的类型来对modals做出修改。
2.注册弹窗
既然我们有了渲染弹窗,那么我们就需要先注册一下弹窗,通过 useDialog API,将所需的弹窗注册到 modals 中。注意,每个弹窗都有一个唯一的id,为modalId,这个Id由 getModalId方法生成。
注册完弹窗后,我们还需要为弹窗注册一个Promise事件,这样在调用useDialog.show()的时候,就是一个promise啦,当然了,有promise,就要有对应的resolve。所以,useDialog API最终会暴露出这几个方法出来,如下所示:
3. show/resolve方法的实现
全局放一个modalCallbacks对象,用来存储每个弹窗的promise事件。需要resolve的时候,我们再通过modalId去进行操作即可。
4.组件内部的resolve
在组件内部,我们也需要用到resolve方法来操控弹窗的关闭。ebay的方案是,使用一个create函数,包裹一个组件后,进行对应的处理。我觉得有些许麻烦,于是乎,我在每个注册的组件中,都自动传入了close方法,用于关闭弹窗。
5.结尾
具体的代码已经上传到codesandbox中了,地址为:codesandbox.io/s/thirsty-s…
有问题评论区可以留言。