state = {
value: null
}
{
this.setState({ value: val });
}}
/>
// Filter组件
// FilterPicker组件
{/* 底部按钮,这个type由外界进行的传递,所以我们需要通过props来进行接收 */}
onSave(type,this.state.value)} />
如果是之前选中了的,当我们再次显示FilterPicker的时候,应该展示默认选中项
// 默认选中的状态
const selectedValues = {
area: ["area", null],
mode: ["null"],
price: ["null"],
more: []
};
...
state = {
...
// 筛选默认选中的状态值
selectedValues
};
const {
...,
selectedValues
} = this.state;
// 默认选中值
let defaultValue = selectedValues[openType];
...
state = {
value: this.props.defaultValue
}
// 保存,隐藏对话框
onSave = (type, value) => {
this.setState({
openType: '',
selectedValues: {
...this.state.selectedValues,
[type]: value
}
});
};
const { titleSelectedStatus, selectedValues } = this.state;
// 创建新的标题选中状态对象
let newTitleSelectedStatus = { ...titleSelectedStatus };
Object.keys(titleSelectedStatus).forEach(key => {
...
});
Object.keys(titleSelectedStatus).forEach(key => {
// key表示数组中每一项
if (key === type) {
// 当前标题
newTitleSelectedStatus[type] = true;
return;
}
...
});
Object.keys(titleSelectedStatus).forEach(key => {
...
// 其他标题
let selectedVal = selectedValues[key];
if (
(key === "area" && selectedVal.length !== 2) ||
selectedVal[0] !== "area"
) {
newTitleSelectedStatus[type] = true;
} else if (key === "more" && selectedVal[0] !== "null") {
newTitleSelectedStatus[type] = true;
} else if (key === "price" && selectedVal[0] !== "null") {
newTitleSelectedStatus[type] = true;
} else if (key === "more") {
// 更多选择
}else {
newTitleSelectedStatus[type] = false;
}
});
this.setState({
titleSelectedStatus: newTitleSelectedStatus,
openType: type
});
封装renderFilterMore方法,渲染FilterMore组件
从filtersData中,获取数据(roomType,oriented,floor,characteristic),通过props传递给FilterMore组件
renderFilterMore() {
// 获取对应数据 roomType,oriented,floor,characteristic
const {
openType,
filtersData: { roomType, oriented, floor, characteristic }
} = this.state;
// 把数据封装到一个对象中,方便传递
const data = {
roomType,
oriented,
floor,
characteristic
};
if (openType !== "more") {
return null;
}
// 传递给子组件
return ;
}
// 渲染标签
renderFilters(data) {
// 高亮类名: styles.tagActive
return data.map(item => {
return (
{item.label}
);
});
}
render() {
const {
data: { roomType, oriented, floor, characteristic }
} = this.props;
return (
...
- 户型
- {this.renderFilters(roomType)}
- 朝向
- {this.renderFilters(oriented)}
- 楼层
- {this.renderFilters(floor)}
- 房屋亮点
-
...
...
);
}
state = {
selectedValues: []
};
this.onTagClick(item.value)}
>
{item.label}
onTagClick(value) {
const { selectedValues } = this.state;
// 创建新数组,尽量不要直接操作原数组
const newSelectedValues = [...selectedValues];
if (selectedValues.indexOf(value) <= -1) {
// 不包含当前的value
newSelectedValues.push(value);
} else {
// 说明包含,就需要移除
const index = newSelectedValues.findIndex(item => item === value);
newSelectedValues.splice(index, 1);
}
this.setState({
selectedValues: newSelectedValues
});
}
// 取消点击事件
onCancel = () => {
this.setState({
selectedValues: []
});
};
// Filter 组件,传递type跟onSave
;
// 确定点击事件,通过props来获取type跟onSave方法
onOk = () => {
const { type, onSave } = this.props;
onSave(type, this.state.selectedValues);
};
// Filter组件
renderFilterMore() {
...
let defaultValues = selectedValues.more
// 传递给子组件
return ;
}
// FilterMore组件
{/* 遮罩层 */}
- 在FilterMore组件中,讲获取到的选中值,设置为子组件状态selectedValues的默认值
state = {
selectedValues: this.props.defaultValues
};
完善FilterTitle高亮功能(★★)
- 在Filter组件的onTitleClick方法中,添加type为more的判断条件
- 当选中值数组长度不为0的时候,表示FilterMore组件中有选中项,此时,设置选中状态高亮
- 点击确定按钮时,根据参数type和value,判断当前菜单是否高亮
// 保存,隐藏对话框
onSave = (type, value) => {
const { titleSelectedStatus } = this.state;
let newTitleSelectedStatus = { ...titleSelectedStatus };
let selectedVal = value;
if (
type === "area" &&
(selectedVal.length !== 2 || selectedVal[0] !== "area")
) {
newTitleSelectedStatus[type] = true;
} else if (type === "mode" && selectedVal[0] !== "null") {
newTitleSelectedStatus[type] = true;
} else if (type === "price" && selectedVal[0] !== "null") {
newTitleSelectedStatus[type] = true;
} else if (type === "more" && selectedVal.length !== 0) {
// 更多选择
newTitleSelectedStatus[type] = true;
} else {
newTitleSelectedStatus[type] = false;
}
this.setState({
openType: "",
titleSelectedStatus: newTitleSelectedStatus,
selectedValues: {
...this.state.selectedValues,
[type]: value
}
});
};
- 在关闭对话框时(onCancel),根据type和当前type的选中值,判断当前菜单是否高亮
// 取消
onCancel = type => {
const { titleSelectedStatus, selectedValues } = this.state;
let newTitleSelectedStatus = { ...titleSelectedStatus };
let selectedVal = selectedValues[type];
if (
type === "area" &&
(selectedVal.length !== 2 || selectedVal[0] !== "area")
) {
newTitleSelectedStatus[type] = true;
} else if (type === "mode" && selectedVal[0] !== "null") {
newTitleSelectedStatus[type] = true;
} else if (type === "price" && selectedVal[0] !== "null") {
newTitleSelectedStatus[type] = true;
} else if (type === "more" && selectedVal.length !== 0) {
// 更多选择
newTitleSelectedStatus[type] = true;
} else {
newTitleSelectedStatus[type] = false;
}
// 隐藏对话框
this.setState({
openType: "",
titleSelectedStatus: newTitleSelectedStatus
});
};
列表找房模块-获取房屋列表数据
目标
- 能够封装筛选条件对象
- 能够获取到房屋列表数据
- 能够实现HouseItem组件在map页面和房屋列表页面的复用
- 能够渲染房屋列表数据在页面
组装筛选条件(★★★)
- 在Filter组件的onSave方法中,根据最新selectedValues组装筛选的条件数据 filters,以下是数据格式
- 获取区域数据的参数名:area 或 subway(选中值,数组的第一个元素)
- 获取区域数据值(以最后一个value为准)
- 获取方式和租金的值(选中值得第一个元素)
- 获取筛选(more)的值(讲选中值数组转换为以逗号分隔的字符串)
// 组拼数据格式
let newSelectedValues = {
...selectedValues,
[type]: value
};
const { area, mode, price, more } = newSelectedValues;
// 筛选条件数据
const filters = {};
// 区域
const areaKey = area[0];
let areaValue = "null";
if (area.length === 3) {
areaValue = area[2] !== "null" ? area[2] : area[1];
}
filters[areaKey] = areaValue;
// 方式和租金
filters.mode = mode[0];
filters.price = price[0];
// more
filters.more = more.join(",");
获取房屋数据(★★★)
- 将筛选条件数据filters传递给父组件HouseList
// 保存,隐藏对话框
onSave = (type, value) => {
...
this.props.onFilter(filters)
...
};
- HouseList组件中,创建方法onFilter,通过参数接收filters数据,并存储到this中
// 提供给Filter组件调用的函数,接受参数 filters
onFilter = filters => {
this.filters = filters;
this.searchHouseList();
};
- 创建方法searchHouseList(用来获取房屋列表数据)
- 根据接口,获取当前定位城市id参数
- 将筛选条件数据与分页数据合并后,作为借口的参数,发送请求,获取房屋数据
// 获取房源列表的函数
async searchHouseList() {
// 获取城市信息
let { value } = JSON.parse(localStorage.getItem("localCity"));
// 请求数据
let res = await instance.get("/houses", {
cityId: value,
...this.filters,
start: 1,
end: 20
});
}
进入页面时获取数据(★★)
- 在componentDidMount钩子函数中,调用searchHouseList,来获取房屋列表数据
- 给HouseList组件添加属性 filters,值为对象
// 初始化属性
filters = {};
- 添加两个状态:list和count(存储房屋列表数据和总条数)
state = {
list: [],
count: 0
};
- 将获取到的房屋数据,存储在state中
// 获取房源列表的函数
async searchHouseList() {
// 获取城市信息
let { value } = JSON.parse(localStorage.getItem("localCity"));
// 请求数据
let res = await instance.get("/houses", {
cityId: value,
...this.filters,
start: 1,
end: 20
});
let { list, count } = res.data.body;
this.setState({
list: list,
count: count
});
}
使用List组件渲染数据(★★★)
- 封装HouseItem组件,实现map和HouseListuemian中,房屋列表项的复用
import React from 'react'
import PropTypes from 'prop-types'
import styles from './index.module.css'
function HouseItem({ src, title, desc, tags, price, onClick }) {
return (
{title}
{desc}
{/* ['近地铁', '随时看房'] */}
{tags.map((tag, index) => {
const tagClass = 'tag' + (index + 1)
return (
{tag}
)
})}
{price} 元/月
)
}
HouseItem.propTypes = {
src: PropTypes.string,
title: PropTypes.string,
desc: PropTypes.string,
tags: PropTypes.array.isRequired,
price: PropTypes.number,
onClick: PropTypes.func
}
export default HouseItem
- 使用HouseItem组件改造Map组件的房屋列表项
renderHousesList() {
return this.state.housesList.map(item => (
)
)
}
- 使用react-virtualized的List组件渲染房屋列表(参考CityList组件的使用)
// 渲染每一行的内容
renderHouseList = ({
key, // Unique key within array of rows
index, // 索引号
style // 重点属性:一定要给每一个行数添加该样式
}) => {
// 当前这一行的
const { list } = this.state;
const house = list[index];
return (
);
};
render(){
return (
...
{/* 房屋列表 */}
)
}