@gyyin
2020-02-06T15:10:46.000000Z
字数 3717
阅读 437
工作
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等等)