• React项目实战之租房app项目(六)渲染房源列表&axios优化&封装顶部搜索栏&列表找房模块之条件筛选


    前言

    一、地图找房模块-获取并渲染房源列表

    1.1 房源列表示例图

    在这里插入图片描述

    1.2 实现步骤

    1、在单击事件中,获取小区下的所有房源数据
    2、展示房源列表
    3、渲染获取到的房源列表
    4、调用地图 panBy() 方法,移动地图到中间位置。
    5、监听地图 movestart 事件,在地图移动时隐藏房源列表。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.3 代码示例

    在src/pages/Map/index.js中添加如下代码:

      // 创建小区覆盖物
      createRect(point, name, count, id) {
        // 创建覆盖物
        const label = new BMap.Label('', {
          position: point,
          offset: new BMap.Size(-50, -28)
        })
    
        // 给 label 对象添加一个唯一标识
        label.id = id
    
        // 设置房源覆盖物内容
        label.setContent(`
          
    ${styles.rect}"> ${styles.housename}">${name} ${styles.housenum}">${count} ${styles.arrow}">
    `
    ) // 设置样式 label.setStyle(labelStyle) // 添加单击事件 label.addEventListener('click', e => { //调用获取房源列表方法 this.getHousesList(id) // 获取当前被点击项 const target = e.changedTouches[0] // 调用地图 panBy() 方法,移动地图到中间位置 this.map.panBy( window.innerWidth / 2 - target.clientX, (window.innerHeight - 330) / 2 - target.clientY ) }) // 添加覆盖物到地图中 this.map.addOverlay(label) }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    获取小区房源数据方法:

      // 获取小区房源数据
      async getHousesList(id) {
        const res = await axios.get(`http://localhost:8080/houses?cityId=${id}`)
        this.setState({
          housesList: res.data.body.list,
    
          // 展示房源列表
          isShowList: true
        })
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    渲染小区房源列表方法:

      // 封装渲染房屋列表的方法
      renderHousesList() {
        return this.state.housesList.map(item => (
          <div className={styles.house} key={item.houseCode}>
            <div className={styles.imgWrap}>
              <img
                className={styles.img}
                src={`http://localhost:8080${item.houseImg}`}
                alt=""
              />
            </div>
            <div className={styles.content}>
              <h3 className={styles.title}>{item.title}</h3>
              <div className={styles.desc}>{item.desc}</div>
              <div>
                {/* ['近地铁', '随时看房'] */}
                {item.tags.map((tag, index) => {
                  const tagClass = 'tag' + (index + 1)
                  return (
                    <span
                      className={[styles.tag, styles[tagClass]].join(' ')}
                      key={tag}
                    >
                      {tag}
                    </span>
                  )
                })}
              </div>
              <div className={styles.price}>
                <span className={styles.priceNum}>{item.price}</span>/</div>
            </div>
          </div>
        ))
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在render方法中渲染房源列表,通过isShowList控制显示与隐藏:

    render() {
        return (
          <div className={styles.map}>
            {/* 顶部导航栏组件 */}
            <NavHeader>地图找房</NavHeader>
            {/* 地图容器元素 */}
            <div id="container" className={styles.container} />
    
            {/* 房源列表 */}
            {/* 添加 styles.show 展示房屋列表 */}
            <div
              className={[
                styles.houseList,
                this.state.isShowList ? styles.show : ''
              ].join(' ')}
            >
              <div className={styles.titleWrap}>
                <h1 className={styles.listTitle}>房屋列表</h1>
                <Link className={styles.titleMore} to="/home/list">
                  更多房源
                </Link>
              </div>
    
              <div className={styles.houseItems}>
                {/* 房屋结构 */}
                {this.renderHousesList()}
              </div>
            </div>
          </div>
        )
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    注意:房源列表相关样式在index.module.css中,这里不做过多展示

    最后,在初始化地图方法中绑定地图移动事件隐藏房源列表:

    // 给地图绑定移动事件
    map.addEventListener('movestart', () => {
      if (this.state.isShowList) {
        this.setState({
          //隐藏房源列表
          isShowList: false
        })
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    二、axios优化

    2.1 问题概述

    当每一次请求接口的时候,都需要写相同的baseUrl。例如:http://localhost:8080
    这样太繁琐,而且当我们的项目部署上线时,很难替换

    2.2 配置生产环境和开发环境

    配置步骤:

    1、在项目根目录中创建文件 .env.development
    2、在该文件中添加环境变量
    //环境变量约定REACT_APP开头
    REACT_APP_URL =http://localhost:8080
    3、重新启动脚手架,脚手架在运行的时候就会解析这个文件
    4、在utils/url.js 中,创建BASE_URL 变量
    5、导出BASE_URL
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    代码示例:
    在src/utils/url.js中添加如下代码:

    // 配置baseURL
    export const BASE_URL = process.env.REACT_APP_URL
    
    最后,可以在其他组件导入使用:
    
    import {BASE_URL} from '../../utils/url.js'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.3 axios优化

    实现步骤:

    1、在utils/api.js 中,导入 axios和BASE_URL
    2、调用 axios.create() 方法创建一个axios实例
    3、给 create 方法,添加配置baseURL,值为 BASE_URL
    4、导出API对象
    
    • 1
    • 2
    • 3
    • 4

    代码示例:
    在src/utils/api.js中添加如下代码:

    import axios from 'axios'
    import { BASE_URL } from './url.js'
    
    // 创建axios的配置文件,里面配置baseURL路径
    const config = {
        baseURL: BASE_URL
    }
    
    // 根据create 方法来构建axios对象
    const instance = axios.create(config)
    
    export { instance }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    三、封装顶部搜索导航栏

    实现步骤:

    1、在components 目录中创建组件 SearchHeader/index.js
    2、把之前写过的结构拷贝到这个文件中
    3、然后把跟首页相关的数据去掉,标题,城市名称
    4、通过props来进行传递
    
    • 1
    • 2
    • 3
    • 4

    代码示例:
    在src/components/SearchHeader/index.js中添加如下代码:

    import { Flex } from 'antd-mobile';
    import React from 'react'
    import {withRouter} from 'react-router-dom'
    import './index.scss'
    import PropTypes from 'prop-types'
    
    function SearchHeader({ history, cityName, className}) {
        return (
            <Flex className={['search-box', className || ''].join(' ')}>
                {/* 左侧白色区域 */}
                <Flex className="search">
                    {/* 位置 */}
                    <div className="location" onClick={() => history.push('/citylist')}>
                        <span className="name">{cityName}</span>
                        <i className="iconfont icon-arrow" />
                    </div>
    
                    {/* 搜索表单 */}
                    <div className="form" onClick={() => history.push('/search')}>
                        <i className="iconfont icon-seach" />
                        <span className="text">请输入小区或地址</span>
                    </div>
                </Flex>
                {/* 右侧地图图标 */}
                <i className="iconfont icon-map" onClick={() => history.push('/map')} />
            </Flex>
        )
    }
    // 设置校验
    SearchHeader.propTypes = {
        cityName: PropTypes.string.isRequired
    }
    export default withRouter(SearchHeader)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    四、列表找房模块-导入顶部导航栏组件

    实现步骤:

    1、在找房页面 SearchHeader 组件基础上,调整结构(添加返回icon等)。
    2、给 SearchHeader 组件传递 className 属性,来调整组件样式,让其适应找房页面效果。
    
    • 1
    • 2

    代码示例:
    然后在src/pages/Houselist/index.js中导入顶部搜索栏组件:

    import React from 'react'
    import { Flex } from 'antd-mobile'
    
    // 导入搜索导航栏组件
    import SearchHeader from '../../components/SearchHeader'
    
    // 导入样式
    import styles from './index.module.css'
    
    // 获取当前定位城市信息
    const { label } = JSON.parse(localStorage.getItem('hkzf_city'))
    
    export default class HouseList extends React.Component {
      render() {
        return (
          <div>
            <Flex className={styles.header}>
              <i
                className="iconfont icon-back"
                onClick={() => this.props.history.go(-1)}
              />
              <SearchHeader cityName={label} className={styles.searchHeader} />
            </Flex>
          </div>
        )
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    最后,在当前目录下创建index.module.css,设置相应的样式

    五、列表找房模块-条件筛选(上)

    5.1 条件筛选效果图

    在这里插入图片描述

    5.2 功能分析

    条件筛选需要具备的功能如下:

    1、点击标题菜单,展开条件筛选对话框,被点击的标题高亮
    2、点击取消按钮或空白区域,隐藏对话框,取消标题高亮
    3、选择筛选条件后,点击确定按钮,隐藏对话框,当前标题高亮
    4、打开对话框时,如果有选择的条件,那么默认显示已选择的条件
    5、打开对话框已经隐藏对话框有动画效果
    6、标题框具有吸顶功能
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    要实现以上功能需要封装4个组件分工合作,分别是:

    1、父组件:Filter
    2、子组件:FilterTitle 标题菜单组件
    3、子组件:FilterPicker 前三个菜单对应的内容组件
    4、子组件:FilterMore 最后一个菜单对应的内容组件
    
    • 1
    • 2
    • 3
    • 4

    5.3 标题菜单组件FilterTitle组件实现

    实现思路:

    1、根据标题菜单数据,渲染标题列表
    2、标题可以被点击
    3、标题点击时高亮,有筛选条件选中时高亮
    4、由父组件Filter提供高亮状态,子组件通过props接受状态来实现高亮
    5、原则是单一数据源,只由父组件Filter提供和修改状态,其他组件只负责接收状态
    
    • 1
    • 2
    • 3
    • 4
    • 5

    实现步骤:

    1、在src/pages/Houselist目录下,新建components文件夹
    2、在components目录下新建Filter,FilterTitle,FilterPicker,FilterMore组件
    3、在FilterTitle组件中通过props接收高亮状态对象 titleSelectedStatus
    4、遍历titleList数组,渲染标题列表
    5、判断高亮对象中当前标题是否高亮,如果是,添加高亮类
    6、给标题项绑定单击事件,在事件中调用父组件传过来的方法 onClick
    7、将当前标题type,通过onClick的参数,传递给父组件
    8、父组件中接收到当前type,修改标题的选中状态为true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    代码示例:
    首先,在src/pages/HouseList/components/Filter/index.js中添加如下代码:

    // 标题高亮状态
    // true 表示高亮; false 表示不高亮
    const titleSelectedStatus = {
      area: false,
      mode: false,
      price: false,
      more: false
    }
    
    export default class Filter extends Component {
      state = {
        titleSelectedStatus
      }
    
      // 点击标题菜单实现高亮
      // 父组件中接收到当前type,修改标题的选中状态为true
      onTitleClick = type => {
        this.setState(prevState => {
          return {
            titleSelectedStatus: {
              // 获取当前对象中所有属性的值
              ...prevState.titleSelectedStatus,
              [type]: true
            }
          }
        })
      }
    
      render() {
        const { titleSelectedStatus } = this.state
    
        return (
          <div className={styles.root}>
            <div className={styles.content}>
              {/* 标题栏 */}
              <FilterTitle
                titleSelectedStatus={titleSelectedStatus}
                onClick={this.onTitleClick}
              />
            </div>
          </div>
        )
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    然后,在src/pages/HouseList/components/FilterTitle/index.js中添加如下代码:

    // 条件筛选栏标题数组:
    const titleList = [
      { title: '区域', type: 'area' },
      { title: '方式', type: 'mode' },
      { title: '租金', type: 'price' },
      { title: '筛选', type: 'more' }
    ]
    
    export default function FilterTitle({ titleSelectedStatus, onClick }) {
      return (
        <Flex align="center" className={styles.root}>
          {titleList.map(item => {
            const isSelected = titleSelectedStatus[item.type]
            return (
              <Flex.Item key={item.type} onClick={() => onClick(item.type)}>
                {/* 选中类名: selected */}
                <span
                  className={[
                    styles.dropdown,
                    // 判断当前的标题是否是选中状态,如果是,设置选中的样式
                    isSelected ? styles.selected : ''
                  ].join(' ')}
                >
                  <span>{item.title}</span>
                  <i className="iconfont icon-arrow" />
                </span>
              </Flex.Item>
            )
          })}
        </Flex>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    总结

    由于篇幅有限,条件筛选其他组件将留到下一篇笔记介绍

  • 相关阅读:
    [linux] depmod和 modprobe
    使用flow捕获js错误提高代码质量
    智慧城市排水系统,管网水位监测仪怎么监测
    git仓库中增加子仓库
    【云原生之Docker实战】使用docker部署DokuWiki知识库系统
    详解Web3社交:一个充满标识证明 、灵魂绑定和NFT的世界
    Redis三种模式——主从复制,哨兵模式,集群
    geant4创建自己的physicslist(以电磁物理为例)
    微信小程序学习(二):常用样式和组件
    海外社媒账号如何运营安全稳定?
  • 原文地址:https://blog.csdn.net/qq_40652101/article/details/128110581