项目背景
时间为下午五点左右,今晚就是项目上线的最后期限,还剩最后两个小功能要做,其中一个功能为解决目前不能点击遮罩区域关闭弹窗的问题。老板希望 小A 和 小B 加加班,毕竟都是小问题,应该很快能解决。小A 觉得也不难,接下了解决无法通过点击遮罩关闭弹窗的任务。
项目技术栈
- 原生微信小程序
需实现的功能
- 实现点击弹窗外的遮罩区域关闭弹窗,但点击弹窗内容区域不会关闭
- 页面中有多个底部弹窗,都需要实现该功能
技术要点
- 需区分不同的弹窗,一个页面中有多个底部弹窗
- 阻止点击子元素(弹窗内容)进行事件冒泡传递
项目原有实现
- 每个底部弹窗都单独有一个布尔值用于控制是否显示
- 每个底部弹窗有单独的方法来控制对应弹窗的布尔值
实现过程
小A 的实现过程:
- 通过搜索很快得出如何实现点击遮罩关闭弹窗,需要给遮罩加上关闭弹窗方法,并给弹窗内容区(非遮罩区域)加上阻止冒泡事件,以免点击弹窗内容也能关闭弹窗
- 通过文档知道微信小程序阻止事件冒泡的方法 catchtap,需要绑定一个方法(可以给一个定义的空的函数)
- 结合1.和2.实现对一个弹窗点击遮罩关闭弹窗的功能
- 因为一个页面有多个底部弹出窗,想到使用微信小程序的自定义组件,这样省去重复定义的逻辑
- 查询文档,了解小程序自定义组件如何实现
- 尝试提取底部弹窗为一个单独的组件并在页面中引入,对引入的底部弹窗组件,每个弹窗传入单独的isShow属性,并定义打开和关闭为同一个方法,方法内部获取isShow值并进行对应逻辑判断
- 发现自定义的组件在某个页面中使用,样式和另一个页面不一样,对比看都是一样的,但最终显示的就是不一样,开始进行问题排查
- 过了一段时间,小A 发现样式问题还是不能解决,决定这个页面还是不用自定义底部弹窗组件,按照之前单个的实现来解决,因为时间来不及了,已经八点多了
- 此时微信响了,老板来问改好了没,并@小B。小B表示,除了小A 的那个任务没解决,其他都解决了。小A 赶紧回复还差一点点,马上就好并提交了代码准备合并。老板@小A 讲这个其实很简单,简述了实现逻辑。小A 回复明白,代码已经提交了,在准备合并。
- 老板看到小A 的代码后表示,你写的太复杂了,为什么要用组件,我来改吧。小A 回复因为觉得这样可以重复利用逻辑,老板回复逻辑是这样没错。
- 小A 默默关闭了要合并的 pr。老板修改完毕,并将修改后的那次 commit 记录分享到群里@小A 和小B 看看。
下面来对比看看 小A 和 老板的实现有什么不同。
自定义底部弹出组件(小A)
- 每个弹窗用自定义的底部弹出组件,在页面中引入
- 给组件传入是否显示的布尔值,如传入 isShow 值为 false,默认不显示该弹窗
- 把阻止弹窗内容冒泡的定义,放到了自定义弹窗组件中
- 对页面引入的每个底部弹窗组件,都传入一个单独的一个布尔值,并单独定义一个方法用于控制弹窗的显隐,内部判断区分显隐的不同逻辑
示意代码:
逻辑
handleOpenAddScheduleModal(e) {
const { isShow } = e.detail;
if (isShow === undefined) {
// 弹窗打开后的相关逻辑
// 主要的功能实现
// 更新 showAddScheduleContentModal 为 true
}
if (isShow === false) {
// 更新 showAddScheduleContentModal 为 false
// 更新其他相关属性进行初始化
this.onCancelAddScheduleModal();
}
}
页面
<bottomModal isShow="{{showAddScheduleContentModal}}" bind:showChange="handleOpenAddScheduleModal">
<view>弹窗内容</view>
</bottomModal>
页面内定义(老板)
- 修改多个定义的布尔值,合并为一个
showingModal,值为字符串/null - 每个弹窗打开,更新 showingModal 的值为指定对应的字符串,如
showingModal: 'updateSchedule' - 关闭弹窗,调用统一的
hideModal方法,设置 showingModal 值为null,showingModal: null以及其他一些值的初始化 - 在页面中对每个弹窗的显隐的判断,采用如
{{ showingModal === 'updateSchedule' ? 'show' : '' }}的方式来进行判断
示意代码:
逻辑
handleOpenAddScheduleModal(e) {
// 弹窗打开后的相关逻辑
// 主要的功能实现
// 更新 showingModal 值为 updateSchedule
}
hideModal() {
// 更新 showingModal 值为 null
// 更新其他值 进行初始化
}
页面
<view class="cu-modal bottom-modal {{ showingModal === 'updateSchedule' ? 'show' : '' }}" bindtap="hideModal">
<view class="cu-dialog rounded-custom rounded-xl" catchtap>
<view>弹窗内容</view>
</view>
</view>
注:catchtap 不绑定一个事件,微信开发者工具会有以下输出
Component "pages/index/index" does not have a method "true" to handle event "tap".
总结
- 组件提取的目的:提取组件的主要目标是简化代码结构和提高可重用性。然而,在本次实现中,小A 的方法未能有效降低代码复杂度,反而引入了不必要的逻辑判断,导致实现过程变得繁琐。
- 功能优先,优化为辅:在项目开发中,首要任务是确保功能的实现,优化应根据实际需求进行,而不是盲目追求代码的简洁性。确保在紧迫的时间框架内完成核心功能是关键。
- 思维方式的灵活性:在处理条件判断时,应打破思维定式,考虑多种可能性。例如,状态的判断不仅限于布尔值,还可以通过对变量值的比较来实现更灵活的逻辑。
- 实际情况的评估:在进行代码优化时,需结合项目的实际情况,评估提取组件或简化逻辑的必要性,以确保最终实现的高效性和可维护性。在本项目中,优化的关键在于将多个布尔值合并为一个字符串,以简化判断逻辑,从而提高代码的可读性和维护性。