好客租房2

54 阅读6分钟

五.首页

1./home/index(去掉/index

  • 把这个的path修改为/home,主要是为了图标的匹配

image.png

把/home/index改为/home,并且加上exact,不加上就会模糊匹配/home,那么每次切换路由 首页的内容都会被匹配上 1 2.默认地址重定向到home页 地址栏只输入域名,如:localhost://3000会自动跳到localhost://3000/home的页面,需要使用重定向redirect

redirect组件用于实现路由重定向,to属性指定要跳转到的路由地址 render属性:是一个函数prop,用于指定要渲染的内容

image.png 六.轮播图 1.安装aiox,yarn add axios 2.在index组件当中导入axios 3.在state当中添加轮播图数据:swipers 4.新建一个方法getSwipers用来获取轮播图数据,并且更新轮播图状态 5/在CommpontDidMount钩子函数当中调用该方法 6.使用获取到的数据渲染轮播图 1.把轮播图的样式拷贝进来,有的浏览器会有 未阻止默认事件的报错,修改下样式可以了

*{
  box-sizing: border-box;
  touch-action: pan-y;
}

但我这边还是不行,是通过注释了node_module的这一段注释

image.png

2.获取数据 安装axios :npm i axios --save

在package.json加上那个这么一段代码:

"proxy": "http://localhost:8080" 1 然后在页面引入axios就可以直接调用:

import axios from 'axios'

axios.get('/swiper')
.then(res => {
    console.log(res)
})
.catch(err => console.log(err))

我这边出现了一个问题就是: 图片src的路径是我自己从其他网站上扒过来的,图片在浏览器地址展示没问题,但奇怪的是在轮播图展示图片的时候报错403.我是在html页面加了一行代码就解决了。

<meta name="referrer" content="no-referrer" />

import React from 'react'
import { Carousel } from 'antd-mobile';

import axios from 'axios'
export default class Index extends React.Component {
    state = {
        //轮播图状态数据
        swipers: []
    }
    async getSwiper() {
        const res = await axios.get('/swiper')
        this.setState({
            swipers:res.data.data
        })
    }
    componentDidMount() {
        this.getSwiper()

    }
    //渲染轮播图
    renderSwipers(){
        return this.state.swipers.map(item => (
            <span
                key={item.id}
                style={{ display: 'inline-block', width: '100%', height: 188 }}
            >
                <img
                    src={item.imgScr}
                    alt=""
                    style={{ width: '100%', verticalAlign: 'top' }}
                />
            </span>
        ))
    }
    render() {
        return (
            <div>
                <Carousel
                    autoplay={false}
                    infinite
                >
                    {this.renderSwipers()}
                </Carousel>
            </div>
        );
    }
}

3.导航菜单 出现的bug: 1)默认进入页面轮播图不会自动轮播 2)切换进入页面,轮播图的高度没有自动撑开

解决的办法: 第一种方法: 根据官网,给state一个默认数据,这样解决了问题,但页面会报错

//轮播图状态数据 swipers: [1,2,3],

第二种方法: 1.在state中添加状态数据

state = {
   //轮播图状态数据
   swipers: [],
  //状态
  isSwiperLoaded: false
}

2.数据加载按成,修改该数据状态值为true

async getSwiper() {
        const res = await axios.get('/swiper')
        this.setState({
            swipers: res.data.data,
            isSwiperLoaded: true
        })
    }

3.只有轮播图数据加载完成的情况下,才渲染轮播图组件

  render() {
        return (
            <div>
                {/* 轮播图 */}
                {
                    this.state.isSwiperLoaded ? (
                        <Carousel
                            autoplay
                            infinite
                        >
                            {this.renderSwipers()}
                        </Carousel>
                    ) : ''
                }


                {/* 导航菜单 */}
                <Flex className="nav">
                    {this.renderNavs()}
                </Flex>
            </div>
        );
    }

第三种方法: 外元素宽度百分百,计算外元素高度 图片原型的高度 /图片原型的宽度 = 外元素的高度/100vw 那么:外元素的高度 = 图片原型的高度 * 100vw / 图片原型的宽度

.am-carousel,.slider-frame,.slider-list{
    height: 50vw!important;
}

整体代码:

import React from 'react'
import { Carousel } from 'antd-mobile';
import { Flex } from 'antd-mobile';
import axios from 'axios'
import './index.css'

import nav1 from '../../assets/images/nav-1.png'
import nav2 from '../../assets/images/nav-2.png'
import nav3 from '../../assets/images/nav-3.png'
import nav4 from '../../assets/images/nav-4.png'
export default class Index extends React.Component {
    state = {
        //轮播图状态数据
        swipers: [],
        flexData: [
            {
                src: nav1,
                text: '整租',
                id: '1',
                path: '/home/list'
            },
            {
                src: nav2,
                text: '合租',
                id: '2',
                path: '/home/news'
            },
            {
                src: nav3,
                text: '地图找房',
                id: '3',
                path: '/home'
            },
            {
                src: nav4,
                text: '整租',
                id: '4',
                path: '/home/profile'
            }
        ],
        isLoad: false,
        isSwiperLoaded: false
    }
    async getSwiper() {
        const res = await axios.get('/swiper')
        this.setState({
            swipers: res.data.data,
            isSwiperLoaded: true
        })
    }
    componentDidMount() {
        this.getSwiper()

    }
    //渲染轮播图
    renderSwipers() {
        return this.state.swipers.map(item => (
            <span
                key={item.id}
                className="swiperItem"
            >
                <img
                    src={item.imgScr}
                    alt=""
                    style={{ width: '100%', verticalAlign: 'top' }}
                />
            </span>
        ))
    }
    renderNavs(){
        return this.state.flexData.map(item => (
            <Flex.Item key={item.id} onClick={() => {
                this.props.history.push(item.path)
            }}>
                <img src={item.src} alt="" />
                <h2>{item.text}</h2>
            </Flex.Item>
        )
        )
    }
    render() {
        return (
            <div>
                {/* 轮播图 */}
                {
                    this.state.isSwiperLoaded ? (
                        <Carousel
                            autoplay
                            infinite
                        >
                            {this.renderSwipers()}
                        </Carousel>
                    ) : ''
                }


                {/* 导航菜单 */}
                <Flex className="nav">
                    {this.renderNavs()}
                </Flex>
            </div>
        );
    }
}

import React from 'react'

// 导入组件
import { Carousel, Flex } from 'antd-mobile'

// 导入axios
import axios from 'axios'

// 导入导航菜单图片
import Nav1 from '../../assets/images/nav-1.png'
import Nav2 from '../../assets/images/nav-2.png'
import Nav3 from '../../assets/images/nav-3.png'
import Nav4 from '../../assets/images/nav-4.png'

// 导入样式文件
import './index.css'

// 导航菜单数据
const navs = [
  {
    id: 1,
    img: Nav1,
    title: '整租',
    path: '/home/list'
  },
  {
    id: 2,
    img: Nav2,
    title: '合租',
    path: '/home/list'
  },
  {
    id: 3,
    img: Nav3,
    title: '地图找房',
    path: '/map'
  },
  {
    id: 4,
    img: Nav4,
    title: '去出租',
    path: '/rent'
  }
]

export default class Index extends React.Component {
  state = {
    // 轮播图状态数据
    swipers: []
  }

  // 获取轮播图数据的方法
  async getSwipers() {
    const res = await axios.get('http://localhost:8080/home/swiper')
    this.setState({
      swipers: res.data.body
    })
  }

  componentDidMount() {
    this.getSwipers()
  }

  // 渲染轮播图结构
  renderSwipers() {
    return this.state.swipers.map(item => (
      <a
        key={item.id}
        href="http://itcast.cn"
        style={{
          display: 'inline-block',
          width: '100%',
          height: 212
        }}
      >
        <img
          src={`http://localhost:8080${item.imgSrc}`}
          alt=""
          style={{ width: '100%', verticalAlign: 'top' }}
        />
      </a>
    ))
  }

  // 渲染导航菜单
  renderNavs() {
    return navs.map(item => (
      <Flex.Item
        key={item.id}
        onClick={() => this.props.history.push(item.path)}
      >
        <img src={item.img} alt="" />
        <h2>{item.title}</h2>
      </Flex.Item>
    ))
  }

  render() {
    return (
      <div className="index">
        {/* 轮播图 */}
        <Carousel autoplay infinite autoplayInterval={5000}>
          {this.renderSwipers()}
        </Carousel>

        {/* 导航菜单 */}
        <Flex className="nav">{this.renderNavs()}</Flex>
      </div>
    )
  }
}

4.tabBar菜单高亮问题 问题:点击首页导航菜单,路由变了,渲染内容也变了,但下面图标高亮没变

image.png

image.png

原因:因为点击图标的时候,没有重新加载Home组件,只是组件路由的切换 解决:在路由切换的时候,也执行菜单高亮的逻辑代码 1.添加componentDidUpdate钩子函数 2.在钩子函数中判断路由地址是否切换(比较前后的两个props,因为路由的信息是通过props传递给组件的) 3.在路由地址切换时,让菜单高亮

    componentDidUpdate(preProps){
        console.log('上一次的路由信息',preProps)
        console.log('当前路有信息',this.props)
        if(preProps.location.pathname!==this.props.location.pathname){
            this.setState({
                selectedTab:this.props.location.pathname
            })
        }
    }

七.node-sass

安装:npm i node-sass
然后就可以直接使用了,把之前的.css结尾的文件改成.scss的文件,然后.scss的文件就可以直接使用语法。
有时候版本太高了会报错,建议手动安装5.0或者6.0的版本

八.租房小组

import React from 'react'
import { Carousel } from 'antd-mobile';
import { Flex } from 'antd-mobile';
import { Grid } from 'antd-mobile';
import { WingBlank } from 'antd-mobile';
import axios from 'axios'
import './index.scss'

export default class Index extends React.Component {
    state = {
        groups: [],
        news: []
    }
    async getGroup() {
        const res = await axios.get('/groups')
        console.log(res)
        this.setState({
            groups: res.data.data
        })
    }
    async getNews() {
        const res = await axios.get('/news')
        this.setState({
            news:res.data.data
        })
        console.log(res)
    }
    componentDidMount() {
        this.getSwiper()
        this.getGroup()
        this.getNews()
    }
    renderNavs() {
        return this.state.flexData.map(item => (
            <Flex.Item key={item.id} onClick={() => {
                this.props.history.push(item.path)
            }}>
                <img src={item.src} alt="" />
                <h2>{item.text}</h2>
            </Flex.Item>
        )
        )
    }
    renderNews() {
        return this.state.news.map(item => (
            <div className="news-item" key={item.id}>
                <div className="imgWrap">
                    <img className="img" src={item.imgSrc} alt="" />
                </div>
                <Flex className="content" direction="column" justify="between">
                    <h3 className="title">{item.title}</h3>
                    <div className="news-from">
                        <span>{item.from}</span>
                        <span>{item.data}</span>
                    </div>
                </Flex>
            </div>
        ))
    }
    render() {
        return (
            <div>
                {/* 租房小组 */}
                <div className="group">
                    <h3 className="title">租房小组
                        <span className="more">更多</span>
                    </h3>
                    {/* 宫格组件 */}
                    <Grid
                        data={this.state.groups}
                        columnNum={2}
                        square={false}
                        hasLine={false}
                        renderItem={(item) => (
                            <Flex className="group-item" justify="around" key={item.id}>
                                <div className="desc">
                                    <p className="title">{item.title}</p>
                                    <span className="info">{item.desc}</span>
                                </div>
                                {/* {item.imgScr} */}
                                <img src={item.imgScr} alt="" />
                            </Flex>
                        )
                        }
                    />
                   
                </div>

                 {/* 最新资讯 */}
                 <div className="news">
                        <h3 className="group-title">最新资讯</h3>
                        <WingBlank size="md">
                            {this.renderNews()}
                        </WingBlank>
                    </div>
            </div>
        );
    }
}

轮播图出现的问题: 不会自动播放,从其他路由返回的时候高度不够 轮播图的数据是动态加载的,加载完成前后,轮播图的数量不一致导致的我呢提 轮播图数据加载完成后渲染他就没有我呢提

如何解决:在state当中添加表示轮播图加载完成的数据, 在轮播图数据加载完成的时候,修改该数据的状态为tru 只有在轮播图数据加载完成的情况下,渲染数据的状态

image.png

第二个问题: 菜单没有出现高效的问题 点击菜跳转的时候出现高亮 点击首页导航菜单,导航到1找房列表页面的时候,找房菜单没有出现高亮

原因: 原来我们实现该功能的时候只考虑了点击以及第一次加载home组件的情况,但是我们没有考虑不重新加载组件的时候路由切换,因为这种情况下,我们的代码没有覆盖到 解决: 思路:在路由切换的时候也执行菜单高亮的代码 1.componmentDidUpdate钩子函数 2.在钩子函数当中判断路由地址是否切换,因为路由切换的信息是通过props传递给组件的,所以通过比较更新前后的两个props

3.在路由切换的时候让菜单高亮

image.png

image.png

componentDiduPDATE 21-在脚手架当中使用sass

image.png

yarn add nod-sasss

image.png groups:[]; getGroups

image.png

image.png

  // 渲染导航菜单
  renderNavs() {
    return navs.map(item => (
      <Flex.Item
        key={item.id}
        onClick={() => this.props.history.push(item.path)}
      >
        <img src={item.img} alt="" />
        <h2>{item.title}</h2>
      </Flex.Item>
    ))
  }

  render() {
    return (
      <div className="index">
        {/* 轮播图 */}
        <div className="swiper">
          {this.state.isSwiperLoaded ? (
            <Carousel autoplay infinite autoplayInterval={5000}>
              {this.renderSwipers()}
            </Carousel>
          ) : (
            ''
          )}
        </div>

        {/* 导航菜单 */}
        <Flex className="nav">{this.renderNavs()}</Flex>

        {/* 租房小组 */}
        <div className="group">
          <h3 className="group-title">
            租房小组 <span className="more">更多</span>
          </h3>

          {/* 宫格组件 */}
          <Grid
            data={this.state.groups}
            columnNum={2}
            square={false}
            hasLine={false}
            renderItem={item => (
              <Flex className="group-item" justify="around" key={item.id}>
                <div className="desc">
                  <p className="title">{item.title}</p>
                  <span className="info">{item.desc}</span>
                </div>
                <img src={`http://localhost:8080${item.imgSrc}`} alt="" />
              </Flex>
            )}
          />
        </div>

        {/* <Flex className="group-item" justify="around">
          <div className="desc">
            <p className="title">家住回龙观</p>
            <span className="info">归属的感觉</span>
          </div>
          <img
            src="http://localhost:3000/static/media/group-1.263b84b0.png"
            alt=""
          />
        </Flex> */}
      </div>
    )
  }
}

image.png

image.png geolocation getCurrentPosition

image.png

image.png 百度地图

image.png 怎么使用的呢

image.png

创建map组件,配置路由, oxtr default class mAp extends React,CIoibb {

image.png

import React from 'react'

// 导入样式
import './index.scss'

export default class Map extends React.Component {
  componentDidMount() {
    // 初始化地图实例
    // 注意:在 react 脚手架中全局对象需要使用 window 来访问,否则,会造成 ESLint 校验错误
    const map = new window.BMap.Map('container')
    // 设置中心点坐标
    const point = new window.BMap.Point(116.404, 39.915)
    // 初始化地图
    map.centerAndZoom(point, 15)
  }
  render() {
    return (
      <div className="map">
        {/* 地图容器元素 */}
        <div id="container" />
      </div>
    )
  }
}

image.png

import React from 'react'

// 导入组件
import { Carousel, Flex, Grid, WingBlank } from 'antd-mobile'

// 导入axios
import axios from 'axios'

// 导入导航菜单图片
import Nav1 from '../../assets/images/nav-1.png'
import Nav2 from '../../assets/images/nav-2.png'
import Nav3 from '../../assets/images/nav-3.png'
import Nav4 from '../../assets/images/nav-4.png'

// 导入样式文件
import './index.scss'

// 导航菜单数据
const navs = [
  {
    id: 1,
    img: Nav1,
    title: '整租',
    path: '/home/list'
  },
  {
    id: 2,
    img: Nav2,
    title: '合租',
    path: '/home/list'
  },
  {
    id: 3,
    img: Nav3,
    title: '地图找房',
    path: '/map'
  },
  {
    id: 4,
    img: Nav4,
    title: '去出租',
    path: '/rent'
  }
]

// 获取地理位置信息
// navigator.geolocation.getCurrentPosition(position => {
//   console.log('当前位置信息:', position)
// })

/* 
  1 打开百度地图JS API 定位文档 。
  2 通过 IP 定位获取到当前城市名称。
  3 调用我们服务器的接口,换取项目中的城市信息(有房源的城市的名称和id)。
  4 将接口返回的城市信息展示在顶部导航栏中。
*/

export default class Index extends React.Component {
  state = {
    // 轮播图状态数据
    swipers: [],
    isSwiperLoaded: false,

    // 租房小组数据
    groups: [],
    // 最新资讯
    news: [],
    // 当前城市名称
    curCityName: '上海'
  }

  // 获取轮播图数据的方法
  async getSwipers() {
    const res = await axios.get('http://localhost:8080/home/swiper')
    this.setState({
      swipers: res.data.body,
      isSwiperLoaded: true
    })
  }

  // 获取租房小组数据的方法
  async getGroups() {
    const res = await axios.get('http://localhost:8080/home/groups', {
      params: {
        area: 'AREA%7C88cff55c-aaa4-e2e0'
      }
    })

    // console.log(res)
    this.setState({
      groups: res.data.body
    })
  }

  // 获取最新资讯
  async getNews() {
    const res = await axios.get(
      'http://localhost:8080/home/news?area=AREA%7C88cff55c-aaa4-e2e0'
    )

    this.setState({
      news: res.data.body
    })
  }

  componentDidMount() {
    this.getSwipers()
    this.getGroups()
    this.getNews()

    // 2 通过 IP 定位获取到当前城市名称。
    const curCity = new window.BMap.LocalCity()
    curCity.get(async res => {
      // console.log('当前城市信息:', res)
      const result = await axios.get(
        `http://localhost:8080/area/info?name=${res.name}`
      )
      // console.log(result)
      this.setState({
        curCityName: result.data.body.label
      })
    })
  }

  // 渲染轮播图结构
  renderSwipers() {
    return this.state.swipers.map(item => (
      <a
        key={item.id}
        href="http://itcast.cn"
        style={{
          display: 'inline-block',
          width: '100%',
          height: 212
        }}
      >
        <img
          src={`http://localhost:8080${item.imgSrc}`}
          alt=""
          style={{ width: '100%', verticalAlign: 'top' }}
        />
      </a>
    ))
  }

  // 渲染导航菜单
  renderNavs() {
    return navs.map(item => (
      <Flex.Item
        key={item.id}
        onClick={() => this.props.history.push(item.path)}
      >
        <img src={item.img} alt="" />
        <h2>{item.title}</h2>
      </Flex.Item>
    ))
  }

  // 渲染最新资讯
  renderNews() {
    return this.state.news.map(item => (
      <div className="news-item" key={item.id}>
        <div className="imgwrap">
          <img
            className="img"
            src={`http://localhost:8080${item.imgSrc}`}
            alt=""
          />
        </div>
        <Flex className="content" direction="column" justify="between">
          <h3 className="title">{item.title}</h3>
          <Flex className="info" justify="between">
            <span>{item.from}</span>
            <span>{item.date}</span>
          </Flex>
        </Flex>
      </div>
    ))
  }

  render() {
    return (
      <div className="index">
        {/* 轮播图 */}
        <div className="swiper">
          {this.state.isSwiperLoaded ? (
            <Carousel autoplay infinite autoplayInterval={5000}>
              {this.renderSwipers()}
            </Carousel>
          ) : (
            ''
          )}

          {/* 搜索框 */}
          <Flex className="search-box">
            {/* 左侧白色区域 */}
            <Flex className="search">
              {/* 位置 */}
              <div
                className="location"
                onClick={() => this.props.history.push('/citylist')}
              >
                <span className="name">{this.state.curCityName}</span>
                <i className="iconfont icon-arrow" />
              </div>

              {/* 搜索表单 */}
              <div
                className="form"
                onClick={() => this.props.history.push('/search')}
              >
                <i className="iconfont icon-seach" />
                <span className="text">请输入小区或地址</span>
              </div>
            </Flex>
            {/* 右侧地图图标 */}
            <i
              className="iconfont icon-map"
              onClick={() => this.props.history.push('/map')}
            />
          </Flex>
        </div>

        {/* 导航菜单 */}
        <Flex className="nav">{this.renderNavs()}</Flex>

        {/* 租房小组 */}
        <div className="group">
          <h3 className="group-title">
            租房小组 <span className="more">更多</span>
          </h3>

          {/* 宫格组件 */}
          <Grid
            data={this.state.groups}
            columnNum={2}
            square={false}
            hasLine={false}
            renderItem={item => (
              <Flex className="group-item" justify="around" key={item.id}>
                <div className="desc">
                  <p className="title">{item.title}</p>
                  <span className="info">{item.desc}</span>
                </div>
                <img src={`http://localhost:8080${item.imgSrc}`} alt="" />
              </Flex>
            )}
          />
        </div>

        {/* 最新资讯 */}
        <div className="news">
          <h3 className="group-title">最新资讯</h3>
          <WingBlank size="md">{this.renderNews()}</WingBlank>
        </div>
      </div>
    )
  }
}

image.png 导入axios,发送请求,页面加载的时候拿到数据 componmentDidMount(){ } gtCityList ({ axios.get();}); 接口地址,p'p

image.png

image.png P134 获取并且处理城市列表


// 数据格式化的方法
// list: [{}, {}]
const formatCityData = list => {
  const cityList = {}
  // const cityIndex = []

  // 1 遍历list数组
  list.forEach(item => {
    // 2 获取每一个城市的首字母
    const first = item.short.substr(0, 1)
    // 3 判断 cityList 中是否有该分类
    if (cityList[first]) {
      // 4 如果有,直接往该分类中push数据
      // cityList[first] => [{}, {}]
      cityList[first].push(item)
    } else {
      // 5 如果没有,就先创建一个数组,然后,把当前城市信息添加到数组中
      cityList[first] = [item]
    }
  })

  // 获取索引数据
  const cityIndex = Object.keys(cityList).sort()

  return {
    cityList,

image.png

/* 
      1 获取热门城市数据
      2 将数据添加到 cityList 中
      3 将索引添加到 cityIndex 中
    */
    const hotRes = await axios.get('http://localhost:8080/area/hot')
    // console.log('热门城市数据:', hotRes)
    cityList['hot'] = hotRes.data.body
    // 将索引添加到 cityIndex 中
    cityIndex.unshift('hot')
    console.log(cityList, cityIndex)
  }

image.png image.png

image.png