React project actual combat rental app project (2) home page module

foreword

1. Home routing processing

Modify the configuration of the home page route: here you need to add the exact attribute.
If it is the default route, you need to jump to /home
and add the following code in src/App.js:

{
    
    /* 配置默认路由 */}
<Route path="/" exact render={
    
    () => <Redirect to="/home"></Redirect>}></Route>

Add the following code in src/pages/home/index.js:

<Route exact path="/home" component={
    
    Index} />

Two, carousel map

2.1 Carousel image rendering

insert image description here

2.2 Copy the carousel component code

1. Open the Carousel component document of the antd-mobile component library
2. Select Basic, click (</>) to display the source code
3. Copy the core code to the Index component
4. Analyze and adjust the code so that it can run in the project

2.3 Detailed explanation of the carousel code

Import components:

import {
    
     Carousel, WingBlank } from 'antd-mobile';

state:

state = {
    
    
    // 图片的名称
    data: ['1', '2', '3'],
    // 图片的高度
    imgHeight: 176,
}

Statement cycle hook function, modify state, set data:

componentDidMount() {
    
    
    // simulate img loading
    setTimeout(() => {
    
    
        this.setState({
    
    
            data: ['AiyWuByWklrrUDlFignR', 'TekJlZRVCjLFexlOCuWn', 'IJOtIlfsYdTyaDTRVrLI'],
        });
    }, 100);
}

structure:

<div className="index">
    <Carousel
        {
    
    /* 自动播放 */}
        autoplay={
    
    false}
        {
    
    /* 无限循环 */}
        infinite
        {
    
    /* 轮播图切换前的回调函数 */}
        beforeChange={
    
    (from, to) => console.log(`slide from ${
      
      from} to ${
      
      to}`)}
        {
    
    /* 轮播图切换后的回调函数 */}
        afterChange={
    
    index => console.log('slide to', index)}
        {
    
    /* 自动切换的时间 */}
        autoplayInterval='2000'
    >    
        {
    
    /* 遍历状态里面的数据,创建对应的a标签和img图片标签 */}
        {
    
    this.state.data.map(val => (
            <a
                key={
    
    val}
                href="http://www.alipay.com"
                style={
    
    {
    
     display: 'inline-block', width: '100%', height: this.state.imgHeight }}
            >
                <img
                    src={
    
    `https://zos.alipayobjects.com/rmsportal/${
      
      val}.png`}
                    alt=""
                    style={
    
    {
    
     width: '100%', verticalAlign: 'top' }}
                    {
    
    /* 图片加载完成的时候调用 */}
                    onLoad={
    
    () => {
    
    
                        window.dispatchEvent(new Event('resize'));
                        this.setState({
    
     imgHeight: 'auto' });
                    }}
                />
            </a>
        ))}
    </Carousel>
</div>

2.4 Refactoring of carousel code

First optimize the corresponding structure and delete unnecessary code

Then get carousel data through axios, install axios: yarn add axios Add
the following code in src/pages/index/Index.js:
import axios, create a new method getSwipers to get carousel data:

import axios from 'axios'

state = {
    
    
    // 轮播图状态
    swipers: [],
}

async getSwipers() {
    
    
    // 请求数据
    let {
    
    data: res} = await axios.get('http://localhost:8080/home/swiper')
    // 判断返回的状态是否是成功
    if(res.status!= 200){
    
    
        console.error(res.description)
        return
    }
    // 把获取到的值设置给state
    this.setState({
    
    
        swipers: res.body
    })
}

Call this method in the componentDidMount hook function:

componentDidMount() {
    
    
    // 调用请求轮播图的方法
   this.getSwipers()
}

Use the obtained data to render the carousel:

// 渲染轮播图的逻辑代码
renderSwipers(){
    
    
    return this.state.swipers.map(item => (
        <a
            key={
    
    item.id}
            href="http://www.itcast.cn"
            style={
    
    {
    
     display: 'inline-block', width: '100%', height: 212 }}
        >
            <img
                src={
    
    `http://localhost:8080${
      
      item.imgSrc}`}
                alt=""
                style={
    
    {
    
     width: '100%', verticalAlign: 'top' }}
            />
        </a>
    ))
}
render() {
    
    
    return (
        <div className="index">
            <Carousel
                autoplay={
    
    true}
                infinite
                autoplayInterval='2000'
            >
                {
    
    /* 调用渲染轮播图的方法 */}
                {
    
    this.renderSwipers()}
            </Carousel>
        </div>
    )
}

2.5 Solve the BUG that appears in the carousel

Our test found that when the page jumps to the home page, the carousel cannot be played automatically and the height is incorrect.
This is because the data of the carousel is dynamically loaded. When switching pages, the data is not loaded yet, and the page is rendered. there will be this problem

Solution:
Modify the following code in src/pages/index/index.js:
Add the status of whether the carousel data is loaded in the state:

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

When the carousel data is loaded, modify this state to true:

async getSwipers() {
    
    
    ...
    // 把获取到的值设置给state
    this.setState({
    
    
        swipers: res.body,
        isSwiperLoaded: true
    })
}

Only when the carousel data is loaded, the carousel component is rendered:
at the same time, wrap a div on the outer layer of the carousel, and set the height of the div:

<div className="swiper">
    {
    
    /* 轮播图 */}
    {
    
    this.state.isSwiperLoaded ? (<Carousel
        autoplay={
    
    true}
        infinite
        autoplayInterval='2000'
    >
        {
    
    /* 调用渲染轮播图的方法 */}
        {
    
    this.renderSwipers()}
    </Carousel>) : ('')}
</div>

3. Navigation menu

3.1 Effect picture of navigation menu:

insert image description here

3.2 Navigation menu implementation

The principle of the navigation menu is to use the Flex component of antd-moblie for layout.
Add the following code in src/pages/index/index.js:
import the navigation menu image:

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'

Write the page layout:

<Flex className="nav">
    <Flex.Item>
        <img src={
    
    nav1} alt=""/>
        <h2>整租</h2>
    </Flex.Item>
    <Flex.Item>
        <img src={
    
    nav2} alt=""/>
        <h2>合租</h2>
    </Flex.Item>
    <Flex.Item>
        <img src={
    
    nav3} alt=""/>
        <h2>地图找房</h2>
    </Flex.Item>
    <Flex.Item>
        <img src={
    
    nav4} alt=""/>
        <h2>去出租</h2>
    </Flex.Item>
</Flex>

Add navigation menu style (index.css):

.nav {
    
    
    padding: 10px 0;
}

.nav img {
    
    
    width: 48px;
}

.nav h2 {
    
    
    font-size: 13px;
    font-weight: 400;
}
/* 通过调试工具我们看到,后续被生成的这个父元素的类名叫am-flexbox-item */
.am-flexbox-item {
    
    
    text-align: center;
}

h2 {
    
    
    margin: 0;
    margin-top: 7px;
}

Encapsulate navigation menu data:

// 导航菜单的数据
const navs = [{
    
    
    id: 0,
    img: nav1,
    title: '整租',
    path: '/home/list'
}, {
    
    
    id: 1,
    img: nav2,
    title: '合租',
    path: '/home/list'
}, {
    
    
    id: 2,
    img: nav3,
    title: '地图找房',
    path: '/home/map'
}, {
    
    
    id: 3,
    img: nav4,
    title: '去出租',
    path: '/home/list'
}]

Create the corresponding method renderNavs, and traverse navs in the method:

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

Finally call this function in the render method:

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

4. Solve the problem that the navigation menu is not synchronized with the TabBar

Problem: When we jump to the corresponding page through the home page menu navigation, the TabBar at the bottom is not highlighted.
Reason: When we implement this function, we only consider the click and the first loading of the Home component. Consider routing switching when the Home component is not reloaded
Solution: When routing switching occurs, process the highlighting of the TabBar
Steps:
1. Add componentDidUpDate hook function
2. Determine whether the routing address is switched in the hook function
3. Add the routing address When switching, make the TabBar correspond to highlight
Code:
Add the following code in src/pages/home/index.js:

// 当Home组件的内容发生更新的时候调用
componentDidUpdate(prevProps) {
    
    
    // 在这里就能判断路由是否进行了切换,路由的信息保存在props属性里面
    // 如果当前的路由信息不等于上一次的,那么就代表发生了路由切换
    if(prevProps.location.pathname !== this.props.location.pathname){
    
    
        this.setState({
    
    
            selectedTab: this.props.location.pathname
        })
    }
}

5. Using Sass

Install Sass: yarn add node-sass
Create a style file with the suffix .scss or .sass
Import the Sass style into the component

6. Housing grouping

6.1 Real estate grouping renderings
insert image description here

6.2 Business logic of house listing grouping

Requirement: Display information of different groups according to the current geographic location
Implementation logic: We first obtain the information of the user's current location, send the information to the background, the background obtains the corresponding content according to the location information, and the front end only needs to display the data

6.3 Realization of house source grouping

Note: Only the default data is displayed here.
Add the following code in src/pages/index/index.js:
Add housing group data in state:

state = {
    
    
    // 租房小组状态
    groups: []
}

Create a new method getGroups to get data:

async getGroups() {
    
    
    let {
    
     data: res } = await axios.get('http://localhost:8080/home/groups', {
    
    
        params: {
    
    
            'area': 'AREA%7C88cff55c-aaa4-e2e0'
        }
    })
    // 判断返回的状态是否是成功
    if (res.status != 200) {
    
    
        console.error(res.description)
        return
    }
    // 把获取到的值设置给state
    this.setState({
    
    
        groups: res.body
    })
}

Call this method in the componentDidMount hook function:

componentDidMount() {
    
    
    this.getGroups()
}

Use the Grid component to realize the structure and style of the listing group:
copy the core code to the Index component:

//自定布局单独抽取成方法
renderGroups(item) {
    
    
    return (
        <Flex className="group-item" justify="around">
            <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 className="group">
    <h3 className="group-title">
        租房小组 <span className="more">更多</span>
    </h3>
    <Grid data={
    
    this.state.groups}
        {
    
    /* 列数 */}
        columnNum={
    
    2}
        {
    
    /* 是否强制正方形 */}
        square={
    
    false}
        {
    
    /* 是否有边框 */}
        hasLine={
    
    false}
        {
    
    /* 自定义里面的布局 */}
        renderItem={
    
    item => this.renderGroups(item)} />
</div>

The corresponding style property (index.scss):

.group {
    
    
    background-color: #f6f5f6;
    overflow: hidden;
    padding: 0 10px;
    .group-title {
    
    
        position: relative;
        margin: 15px 0px 15px 10px;
        font-size: 15px;
        .more {
    
    
            color: #787d82;
            position: absolute;
            right: 0;
            font-size: 14px;
            font-weight: normal;
        }
    }
    // 覆盖默认背景色
    .am-grid .am-flexbox {
    
    
        background-color: inherit;
        .am-flexbox-item .am-grid-item-content {
    
    
            padding: 0;
            padding-bottom: 10px;
        }
    }
    .group-item {
    
    
        height: 75px;
        .desc {
    
    
            .title {
    
    
                font-weight: bold;
                font-size: 13px;
                margin-bottom: 5px;
            }
            .info {
    
    
                font-size: 12px;
                color: #999;
            }
        }
        img {
    
    
            width: 55px;
        }
    }
    .am-flexbox-align-stretch {
    
    
        margin-bottom: 10px;
        .am-grid-item {
    
    
            background-color: #fff;
            &:first-child {
    
    
                margin-right: 10px;
            }
        }
    }
}

7. Latest information

7.1 Latest information renderings

insert image description here

7.2 Data Acquisition & Page Rendering

Add the following code in src/pages/index/index.js:

    state = {
    
    
        // 最新资讯
        news: []
    }


async getNews() {
    
    
    let {
    
     data: res } = await axios.get('http://localhost:8080/home/news?area=AREA%7C88cff55c-aaa4-e2e0')
    // 判断返回的状态是否是成功
    if (res.status != 200) {
    
    
        console.error(res.description)
        return
    }
    // 把获取到的值设置给state
    this.setState({
    
    
        news: res.body
    })
}

  componentDidMount() {
    
    
    this.getNews()
  }

renderNews() {
    
    
  return this.state.news.map(item => {
    
    
     return (
         <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>
     )
})

7.3 Solve the problem that the content is suppressed by the TabBar

We find the div box that wraps the route and the bottom navigation bar in Home.js, and add padding-bottom attribute to it

Summarize

Guess you like

Origin blog.csdn.net/qq_40652101/article/details/127470496