基于Umi搭建的个人Dva脚手架(三) - 多Layout设计

1、基本概述

   在项目开发过程中,通常的企业后台系统会包含头部(Header)、侧边栏(Sider),主体内容(Content)以及底部(Footer)。通常情况下我们会在Layout文件中布局,并对头部、侧边栏、底部封装成对应的组件,而针对主体内容部分,通过路由来控制显示不同的内容。

   但是也存在一些页面不需要按照上边的布局方式来展示,例如登录、注册,或者其他类似的页面。

   针对上述情况,通常情况下,我们会封装多个全局的Layout,根据对路由的判断,来确定具体的加载哪一个Layout。

  在Umi.js的API中 https://umijs.org/zh/guide/router.html#%E5%85%A8%E5%B1%80-layout ,我们可以找到下边的答案:

  约定 src/layouts/index.js 为全局路由,返回一个 React 组件,通过 props.children 渲染子组件。

export default function(props) {
 return (
   <>
     <Header />
     { props.children }
     <Footer />
   </>
 );
}

  你可能需要针对不同路由输出不同的全局 layout,umi 不支持这样的配置,但你仍可以在 layouts/index.js 对 location.path 做区分,渲染不同的 layout 。比如想要针对 /login 输出简单布局,

export default function(props) {
  if (props.location.pathname === '/login') {
    return <SimpleLayout>{ props.children }</SimpleLayout>
  }
  
  return (
    <>
      <Header />
      { props.children }
      <Footer />
    </>
  );
}

  全局的Layout需要放置在根目录下Layouts文件夹下(index文件),全局Layout可以理解为一级路由。

2、核心代码分析

  Umi.js的文档中提供的方法原理上是对的,但是也存在一些问题。如果不同的全局Layout之间存在一些复杂的业务处理,或者需要在对应的生命周期中处理一些方法时,就会存在功能职责不单一,不利于后期的维护。针对上述问题,做如下改进:

import React from 'react';
import {connect} from 'dva';
import BasicLayout from "./BasicLayout";
import UserLayout from "./UserLayout";
import {userLayoutConfig} from "./config";

class Index extends React.Component {
    render() {
        const {location} = this.props,
            {pathname} = location;

        if (userLayoutConfig && userLayoutConfig.includes(pathname)) {
            return <UserLayout {...this.props} />;
        }

        return (
            <BasicLayout {...this.props} />
        );
    }
}


export default connect(({global}) => ({global}))(Index);

  其中BasicLayout、UserLayout为不同场景下的全局Layout,userLayoutConfig变量中配置需要渲染UserLayout的场景,通过改造之后,实现了BasicLayout、UserLayout的分离,在各自的组件内可以根据不同的场景进行布局,也可以维护各自的生命周期,以及组件内的逻辑(包含头部信息、鉴权、退出等等),具体的实现可以自行根据各自的业务进行,可以参考BasicLayout、UserLayout中的写法。

  以BasicLayout为例,做简要说明,核心代码如下:

import styles from './index.less';
import React from 'react';
import {LocaleProvider, Layout} from 'antd';
import zhCN from 'antd/lib/locale-provider/zh_CN';
import router from 'umi/router';
import {MyHeader, MySider} from '../components';

const {Header, Sider, Content} = Layout;

/*页面布局,可以理解为一级路由*/
export default class BasicLayout extends React.Component {


    componentDidMount() {
        const {dispatch} = this.props;
        /*查询用户信息*/
        dispatch({
            type: 'global/queryUserInfo',
        })

        /*查询菜单数据*/
        dispatch({
            type: 'global/queryMenuList'
        });
    }

    render() {
        const {global, children, dispatch} = this.props;
        const {userInfo, menuList} = global;

        const headerProps = {
            userInfo,
            onExit: () => {
                dispatch({
                    type: 'global/exit',
                }).then(() => {
                    router.push('/login');
                });
            },
        };
        const siderProps = {
            menuList,
        };
        const MyFooter = () => (
            <div className={styles.footerContent}>Copyright © 2018产品技术部出品</div>
        );

        return (
            <LocaleProvider locale={zhCN}>
                <Layout className={styles.normal}>
                    <Header>
                        <MyHeader {...headerProps} />
                    </Header>
                    <Layout>
                        <Sider width="170">
                            <MySider {...siderProps} />
                        </Sider>
                        <Content className={styles.contentWrap}>
                            <div className={styles.content}>{children}</div>
                            <MyFooter/>
                        </Content>
                    </Layout>
                </Layout>
            </LocaleProvider>
        );
    }
}


  BasicLayout通过Header、Sider、Content的组件进行布局,并通过LocaleProvider设置国际化;在生命周期componentDidMount中获取用户信息(queryUserInfo)以及获取动态菜单的数据(queryMenuList),关于动态菜单的渲染,在下一章节中,会做详细说明。如果涉及的其他的具体业务,可以自行调整。


上一篇:基于Umi搭建的个人Dva脚手架(二) - HTTP请求的封装
下一篇:基于Umi搭建的个人Dva脚手架(四) - 可配置的表单组件封装


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值