@gyyin
2020-02-06T07:10:46.000000Z
字数 3717
阅读 697
工作
IBU的筛选项看起来和2.0有很大不同,主要体现在UI上面,然而从逻辑上来看,两者几乎保持一致。

首先,Sort和原来的排序保持一致,都是一层单选项,Area和原来的位置区域一样,两层筛选,而Filter和原来的都不一样,Filter包括了滑动条、星级选择以及单选项和多选项。
如果还原成2.0的样子,Filter实际上是三层筛选,一级筛选应该有价格、星级、含早、床型,二级筛选则是价格分类(含出租车和小费、不含出租车和小费等等),星级(一星、二星、三星),是否含早(含早、不含早)、床型(大床、双床、三床),三级筛选则是价格分类下的不同价格、不同品牌分类下的不同品牌的酒店。

这也意味着Filter筛选项至少有一级(星级、是否含早等),最多有三级(价格、品牌等等),底部的show results和右上角的clear与原来2.0的确认和恢复默认一致。
快捷筛选项需要和筛选项进行联动,也有单选和多选两种形式。
如果选择某一分类下的筛选项,那么需要和相同分类的快捷筛选项联动(默认选中),反之亦然。
列表卡片需要展示一些基本信息,点击卡片可以跳转至详情页。
按照业务逻辑划分store,可以选择将action放入对应store中,也可以单独将action拆分出来,但是这里的筛选项差异较大,交互也比较复杂,也很容易导致model互相耦合,不适合采用前者的方式,所以这里我选择把action拆分出来,只传入需要的store,类似于redux的action和reducer。
这个store的设计和原来的hotelList store设计没有太大区别,主要划分为这么几个大类:

其他交互的实现都很简单,这里主要讲一下筛选项和快捷筛选项的设计。
因为筛选项和快捷筛选项需要联动,这里不适合给筛选项添加selected标识,所以需要在store中存一份已选的数据,在渲染的时候映射到对应的筛选项or快捷筛选项。
筛选项只有在选择后并点击确认按钮才会存入store,如果没有点击确认按钮,那么就不会存入store,所以选中的筛选项状态在组件内部用state来保存,一旦点击恢复默认按钮就clear state。
这里的筛选项数据结构如下:
const store = {// 互斥筛选项类mutualFilters: {"filter": [["price", "brand"]],"area": [],"sort": []},// class和category保证能更快查找到// 快捷筛选项中的class可以将key以"-"分割后的数组长度来判断是在categories、filterItems还是filterLastItems里面// isQuick用来判断带给酒店详情页的筛选项是快捷还是普通// observable监听selectedFilter,每次变化时在reaction里面调用接口selectedFilter: [{key: "filter-price-1",category: "filter",class: "filterItems",isQuick: true,isRadio: true,name: "虹桥火车站"}, {key: "sort-1",class: "categories",category: "sort",isRadio: true,name: "按价格排序"}],filterList: {"filter": {name: "filter",items: ["filter-price", "filter-brand", "filter-star"]},"area" : {name: "area",items: ["area-1", "area-2", "area-3"]},// sort需进行特殊处理"sort": {name: "sort",items: ["sort-1", "sort-2", "sort-3"]}},// 保证快捷筛选项的顺序quickFilterSort: ["filter-bed-1", "filter-price-2"],entities: {"quickFilter": {"filter-bed-1": {isRadio: true,key: "filter-bed-1",name: "大床",value: 1}},"activeFilter": "filter",// 如果items为空,意味着当前已经是最后一层了,没有子筛选项了"categories": {"filter": {"filter-price": {categoryName: "price",name: "价格",key: "filter-price",category: "filter",class: "categories",id: "1",items: ["filter-price-1", "filter-price-2", "filter-price-3"]},"filter-brand": {categoryName: "brand","name": "品牌",category: "star",class: "categories",key: "filter-brand",id: "2",items: ["filter-brand-1", "filter-brand-2", "filter-brand-3"]},"filter-star": {categoryName: "star","name": "星级",category: "star",class: "categories",key: "filter-star",id: "3",items: ["filter-star-1", "filter-star-2", "filter-star-3"]},},"area": {"area-1": {key: "area-1",id: "1",category: "area",class: "categories",items: ["area-1-1", "area-1-2", "area-1-3"]},"area-2": {key: "area-2",id: "2",category: "area",class: "categories",items: ["area-2-1", "area-2-2", "area-2-3"]},"area-3": {key: "area-3",id: "3",category: "area",class: "categories",items: ["area-3-1", "area-3-2", "area-3-3"]}},"sort": {"sort-1": {key: "sort-1",category: "sort",class: "categories",name: "按照价格排序",isRadio: true,id: "2",items: []}}},"filterItems": {"filter-price-1": {key: "filter-price-1",name: 500,category: "filter",class: "filterItems",isRadio: true,items: []},"area-1-1": {key: "filter-price-1",category: "area",class: "filterItems",isRadio: true,name: "虹桥火车站",items: []},},// 拥有三层的筛选项(例如brand,结构和filterItems类似)"filterItems": {}}}
理想情况下是这种扁平化的结构,根据filterCategory-id-value作为key来查找对应的筛选项,复杂点在于怎么format数据。
当选择筛选项的时候,会保存对应的项到selectedFilter里面,quickFilter会根据key来匹配,展示自己是否选中。
当选择快捷筛选项的时候,也是同理。
以filter组件为维度设计state,在componentWillReceiveProps中将selectedFilter赋给state,结构和selectedFilter类似,state中的值会映射到当前打开的筛选项里面,如果点击确定后会存入store。
如果是筛选项,那么会从父组件将items传下来,在组件内部的state里面根据isRadio来处理。
如果是筛选项类,那就根据mutualFilters中的互斥关系,对state进行处理,比如brand和bed互斥,当我选bed中的筛选项,那就clear掉state中的brand。
如果是快捷筛选项,也会根据selectedFilter里面选中的项进行对比(一般来说肯定可以拿到isRadio和两者关联的某个值,可能是id也可能是type等等)