一般地,首页需要在全局路由的基础上,增加页面路由功能。

因为首页有导航,有页头、页尾这些固定的布局,而内容板块可以随导航而变动。这时候全局路由已经不能满足页面局部刷新的需求。

假设首页架构页面是一个独立组件,并称为父组件,Content内容由各导航所对应的页面组件按需替换加载。则页面内跳转有如下情况。

1、父组件跳转子组件;
2、子组件跳转兄弟组件;

父组件跳转子组件

这个实现简单,只要在父组件的Content区域,用子组件替换即可。

  1. 父组件代码:
    contentView = () => {
        switch (this.state.infoType) {
            case 'dashboard':
                console.log('Dashboard')
                return <MainPage jumpFunc={this.jumpFunc} />

            case 'team':
                console.log('TeamConfig')
                return <TeamConfig />

            case 'project':
                console.log('ProjectList')
                return <ProjectList jumpFunc={this.jumpFunc} />

            case 'projectDetail':
                console.log('ProjectDetail')
                return <ProjectDetail jumpFunc={this.jumpFunc} params={this.state.params} />

            case 'codeReview':
                console.log('Code Review')
                return <CodeReview />

            case 'base':
                return <MyInfo userid='666' infoType='base' />

            case 'sec':
                return <MyInfo userid='666' infoType='sec' />
            default:
                break;
        }
        return <MyInfo userid='666' infoType='sec' />
    }

 render() {
        return (
            <Layout>
                <Sider
                    width='250'
                    trigger={null}
                    collapsible
                    collapsed={this.state.collapsed}>
                    <div className='naviHeader'>
                        <img src={logo} className="headerLogo" />
                    </div>
                    <Menu
                        defaultSelectedKeys={['1']}
                        defaultOpenKeys={['sub1']}
                        mode="inline"
                        theme="dark"
                        inlineCollapsed={this.state.collapsed}
                        onSelect={this.tabSelect}
                    >
                        <Menu.Item key="dashboard" className='naviCell'>
                            <Icon type="dashboard" style={{ fontSize: 20 }} />
                            <span className='naviItemTitle'>Dashboard</span>
                        </Menu.Item>
                        <Menu.Item key="project" className='naviCell'>
                            <Icon type="code" style={{ fontSize: 20 }} />
                            <span className='naviItemTitle'>Project</span>
                        </Menu.Item>
                        <Menu.Item key="codeReview" className='naviCell'>
                            <Icon type="code" style={{ fontSize: 20 }} />
                            <span className='naviItemTitle'>Code Review</span>
                        </Menu.Item>
                        <Menu.Item key="tool" className='naviCell'>
                            <Icon type="tool" style={{ fontSize: 20 }} />
                            <span className='naviItemTitle'>Dev Tools</span>
                        </Menu.Item>
                        <Menu.Item key="team" className='naviCell'>
                            <Icon type="team" style={{ fontSize: 20 }} />
                            <span className='naviItemTitle'>Team Config</span>
                        </Menu.Item>
                    </Menu>
                </Sider>
                <Layout>
                    <Header style={{ background: '#fff', padding: 0 }} className='myInfoHeader'>
                        <Icon
                            className="trigger"
                            type={this.state.collapsed ? 'menu-unfold' : 'menu-fold'}
                            style={{ paddingLeft: 20 }}
                            onClick={this.toggle}
                        />
                        <div className='myInfo'>
                            <Dropdown overlay={this.menu}>
                                <a className="ant-dropdown-link myInfoEntrance" href="#">
                                    <Icon type="user" />
                                    <div style={{ paddingLeft: 10 }}>朱老板</div>
                                </a>
                            </Dropdown>
                        </div>
                    </Header>
                    <Content
                        style={{
                            minHeight: 800,
                        }}
                    >
                        {this.contentView()}
                    </Content>
                </Layout>
            </Layout>
        );
    }

父组件是通过Layout布局进行整体架构,Sider控制Content显示的内容。

contentView方法里面通过判断key值进行不同子组件的展示。

兄弟组件直接互相跳转。

父组件跳转子组件容易,那子组件如何跳转到其他子组件呢?

如果通过全局路由,必定会引起页面整体刷新,不利益体验。

如何自定义局部路由?

这就是问题的关键。

其实需要用到状态提升(或者说共用状态)

跳转步骤如下:

  1. 在父组件中定义跳转方法,并可以传入参数(包括跳转的页面,以及页面所需参数),并将方法绑定到全局状态;
  2. 子组件中定义跳转方法,并将方法绑定到全局状态;
  3. 在子组件跳转方法中获取父组件方法并传入需要跳转的兄弟组件参数进行调用;

1、定义父组件跳转方法

class ARLayout extends React.Component {
    constructor(props: any) {
        super(props)
        this.jumpFunc = this.jumpFunc.bind(this);

    }
    state = {
        collapsed: false,
        contentView: <MyInfo userid='666' infoType='base' />,
        infoType: 'base',
        params: '',
    };


    jumpFunc(type: any, param: any) {
        this.setState({
            infoType: type,
            params: param,
        });
    }
    contentView = () => {
        switch (this.state.infoType) {
            case 'dashboard':
                console.log('Dashboard')
                return <MainPage jumpFunc={this.jumpFunc} />

            case 'team':
                console.log('TeamConfig')
                return <TeamConfig />

            case 'project':
                console.log('ProjectList')
                return <ProjectList jumpFunc={this.jumpFunc} />

            case 'projectDetail':
                console.log('ProjectDetail')
                return <ProjectDetail jumpFunc={this.jumpFunc} params={this.state.params} />

            case 'codeReview':
                console.log('Code Review')
                return <CodeReview />

            default:
                break;
        }
        return <MyInfo userid='666' infoType='sec' />
    }


 ……
}

关键代码1、需在构造方法里面绑定this,这样就可以在其他页面访问到jumpFunc方法;

constructor(props: any) {
        super(props)
        this.jumpFunc = this.jumpFunc.bind(this);

    }

关键代码2、在跳转代码里刷新参数,刷新之后会重新更新布局。

 jumpFunc(type: any, param: any) {
        this.setState({
            infoType: type,
            params: param,
        });
    }

2、定义跳转的子组件

class ProjectList extends React.Component<any> {
    constructor(props: any) {
        super(props);
        this.showDetail = this.showDetail.bind(this);
    }

    showDetail(item: any) {
        this.props.jumpFunc("projectDetail", item);
        console.log("projectName:" + item.projectName);
    };
}

关键代码1、在构造方法里给跳转方法绑定this;
关键代码2、在跳转方法里获取父组件的跳转方法,并调用;
关键代码3、因为构造方法入参是any类型,所有类的继承也要加上any(React.Component<any>);

3、被跳转的子组件,接收跳转参数

import React from "react";
import "./ProjectDetail.css";
import ProjectDetailHeader from "./ProjectDetailHeader";
import ProjectDetailPanelLint from "./ProjectDetailPanelLint";
import { Layout, Row, Col } from "antd";
import ProjectDetailPanelAutoTest from "./ProjectDetailPanelAutoTest";
import ProjectDetailPanelCICD from "./ProjectDetailPanelCICD";
const { Header, Content, Footer, Sider } = Layout;

class ProjectDetail extends React.Component<any> {

    render() {
        return (
            <Layout className="pd-body">
                <Header className="pd-header" style={{ background: '#fff', padding: 0, height: 240 }}>
                    <ProjectDetailHeader jumpFunc={this.props.jumpFunc} params={this.props.params} />
                </Header>
                <Content style={{ background: 'none', padding: 0, margin: 24 }}>
                    <div className="pd-content">
                        <Row>
                            <Col span="24">
                                <div className="pd-panel">
                                    <ProjectDetailPanelCICD />
                                </div>
                                <div className="pd-panel">
                                    <ProjectDetailPanelLint />
                                </div>
                                <div className="pd-panel">
                                    <ProjectDetailPanelAutoTest />
                                </div>
                            </Col>
                        </Row>
                    </div>
                </Content>
            </Layout>
        );
    }
}

export default ProjectDetail;

上面代码接收参数之后又直接透传给了子组件:

<ProjectDetailHeader jumpFunc={this.props.jumpFunc} params={this.props.params} />

子组件也通过同样的方式(this.props.params)获取参数,然后展示。

以上就是局部跳转的全部内容,欢迎留言交流。