![640?wx_fmt=gif](https://img-blog.csdnimg.cn/img_convert/916e886bd6838e210711cb33aebf4755.png)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/85f546d110647a5b0c8d30b7525fc225.png)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/4a7cdc3376a920214c0f1cc0f8b4cbdd.png)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/4a7cdc3376a920214c0f1cc0f8b4cbdd.png)
![640](https://img-blog.csdnimg.cn/img_convert/7aa7e5a0f1f864e23a5ed17f3917cb26.png)
此文前端框架使用 rax,全篇代码暂未开源(待开源)
前言
貌似在面试中,你如何设计一个 react/vue 组件,貌似已经是司空见惯的问题了。本文不是理论片,更多的是自己的一步步思考和实践。文中会有很多笔者的思考过程,欢迎评论区多多交流和讨论。
从需求讨论、技术方案探讨到编码、到最终的测试,经历过了很多次的脑暴,也遇到过非常多的坑,其中有可能跟业务有关、也有可能跟框架有关,基于这些坑,又讨论了很多解决方案和非常 hack(歪门邪道)的对策。但是随着时间的推移,再回头看看当时的 hack 代码,很多都不太记得为什么这么写了,所以这里简单记录下,Filter 组件的开发过程。以便后面查询,更希望能大家一起探讨,以求得更优质的代码架构和实现思路。
由于代码编写使用基于底层 weex 的 rax 框架,所以有些坑,或许对于正在使用 react 或者 vue 的你并不会遇到,可以直接忽略
说说业务
Filter,已经常见的不可再常见的组件了,顾名思义,就是个筛选过滤器。我们先看看现有 app 上的一些 filter 展现 形式。既然做组件,我们就需要它足够的通用,足够的易于扩展。
在说 Filter 的业务特征之前,我们先约束下每一部分的命名,以便于你更好的阅读此文:
上面分别是拍卖和飞猪的 filter 页面,从这两个页面中,我们大概可以总结出关于 Filter 的一下几点业务画像:
最终组件产出
由于 rax 1.0 ts+hooks 开源版本还在开发中,所以仓库链接暂时就不放上了
效果图:
console
处可见抛出的查询参数
设计与思考
前端组件架构图(初版)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/9da27d350485aded2bb2dff764cc7f05.png)
组件架构图(终板)
![640?wx_fmt=png](https://img-blog.csdnimg.cn/img_convert/b77dd2c77b5d5f89df97f5cc4f3f8a2a.png)
src├─ Filter.js //Filter 最外层父容器├─ constant.js //项目代码常量定义├─ index.js //入口文件├─ navbar // navBar 文件夹│ ├─ NavBase.js //navBar 基类 NavQuickSearch 和 NavRelatePanel 父类│ ├─ NavQuickSearch.js // 快速搜索(无 panel)的 navBar│ ├─ NavRelatePanel.js // 带有 panel 的 navBar│ └─ index.js // 导出文件├─ panel│ └─ index.js // panel 面板组件代码└─ style.js//Filter 最外层父容器
├─ constant.js //项目代码常量定义
├─ index.js //入口文件
├─ navbar // navBar 文件夹
│ ├─ NavBase.js //navBar 基类 NavQuickSearch 和 NavRelatePanel 父类
│ ├─ NavQuickSearch.js // 快速搜索(无 panel)的 navBar
│ ├─ NavRelatePanel.js // 带有 panel 的 navBar
│ └─ index.js // 导出文件
├─ panel
│ └─ index.js // panel 面板组件代码
└─ style.js
组件功能 Feature
这里指的是 Filter 的功能 Feature,跟上文提及的 Filter 组件功能可能并不能完全覆盖,但是我们提供解决方案,组件的设计始终秉持着不侵入业务的原则,所有与业务相关均给予配置入口。
期望组件使用形式
import Filter from 'rax-pui-filter'; render( <Filter navConfig={[]} onChange={()=>{}}> <Filter.Panel> <业务组件1 /> </Filter.Panel> <Filter.Panel> <业务组件2 /> </Filter.Panel> </Filter> );
render(
<Filter
navConfig={[]}
onChange={()=>{}}>
<Filter.Panel>
<业务组件1 />
</Filter.Panel>
<Filter.Panel>
<业务组件2 />
</Filter.Panel>
</Filter>
);
组件功能与业务需求边界划分
何为业务功能何为组件功能,这个需要具体的探讨,其实也没有严格意义上的区分。说白了,就是你买个手机,他都会送你充电器。但是。。。为什么很多手机也送手机壳(小米、华为、荣耀)但是 iPhone 却不送呢?所以到底是不是标配?
对于我们这个组件,简而言之:我们能做到的,我们都做!但是其中我们还是梳理出某些功能还是数据业务功能:
换言之,Filter 里面任何功能都可以说为业务功能。但是我们需要提供 80%业务都需要的功能封装作为 Filter 的 Future。这就是我们的目的。
根据上面的业务功能和组件功能的区分,我们就知道在使用 Filter 的时候,你应该给我传递什么配置,以及什么方法。
Filter API
参数 | 说明 | 类型 | 默认值(是否必填) |
---|---|---|---|
navConfig | 筛选头配置, 点击查看详细配置项 效果图 ![]() |
Array<Object> | - (必填) |
offsetTop | Filter组件展开面板状态下距离页面顶部的高度,有两种状态:固定位置和跟随页面滚动吸附置顶 固定位置 状态下距离页面顶部的高度 跟随页面滚动吸附置顶: 状态下距离页面顶部的高度 效果图 ![]() |
Number | 0 |
styles | 配置样式,Filter中所有样式都可使用styles 集合对象来配置覆盖styles 格式 ![]() |
Object | {} |
getStickyRef | 获取 Sticky 节点的 ref 实例,用于滚动吸附场景,内部配合 pm-app-plus 容器组件点击 Filter 时自动吸附置顶示例图 ![]() |
Function | |
keepHighlight | 筛选条件改变后是否需要在筛选头保持高亮 效果图 ![]() |
Boolean | false |
clickMaskClosable | 开启 mask 背景的点击隐藏 | Boolean | true |
onChange | Filter 搜索变更回调函数 签名: Function(params:Object,index:Number, urlQuery: Object) => void 参数: params: Object 搜索参数index:Number 触发搜索的 Panel 搜索urlQuery:Object URL query 对象 |
Function | < |