美文网首页React我爱编程程序员
Material-UI-React-Layout-响应式布局

Material-UI-React-Layout-响应式布局

作者: zhyuzh3d | 来源:发表于2018-05-08 19:04 被阅读2082次

    React+Electron桌面应用开发文章索引

    继续前面的文章,这篇文章介绍基于MaterialUI的响应式布局方法。所谓响应式布局就是指在不同屏幕设备(如手机、平板、PC)上显示不同的布局格式,主要是根据屏幕宽度调整不同来匹配不同的布局,高度自动拉长或缩短。(一般主要是排列方式的改变,而内容并没有太大变化)

    MaterialUI官方说明
    MaterialDesign官方解说


    断点BreakPoints

    当页面宽度超过或低于某个像素数字的时候,我们就切换到新的布局,这个数字叫做断点BreakPoint.

    MaterialUI默认的断点是:

    • xs, extra-small: 0px or larger
    • sm, small: 600px or larger
    • md, medium: 960px or larger
    • lg, large: 1280px or larger
    • xl, xlarge: 1920px or larger
    响应式布局的断点

    12栏布局

    Material design默认把屏幕竖向分隔为12栏,使用柔性盒技术Flex box来实现。

    来自网络的flexbox 布局教程

    我们把网格单元Grid分为两类进行布局:Container容器和Item填充项目。

    Item用百分比设定宽度,也就是它总是占父层的百分之多少,跟着父层一起放缩。Item之间有间隔,由父层Container的空隙spacing决定。

    为了去除页面最外面的空隙,我们把body的边缘都去掉,打开index.html修改

    <body style="margin: 0;padding: 0">
    

    自动排列内容

    下面是新的HomePage.js的代码,请注意render()里面:

    • 我们先创建12个items,每个item里面放一个卡片Card。
    • 最后创建一个Grid容器container,把12个item放进去。
    • 注意item设定xs=12,表示在极小屏幕(也就是宽度小于600像素)的时候,它占12栏充满父层;随着屏幕变大,超过600但小于960的时候,sm=6表示占父层的一半;以此类推。
    import {
        Component
    } from 'react'
    import h from 'react-hyperscript'
    
    import Button from 'material-ui/Button'
    import Grid from 'material-ui/Grid'
    import Card, {
        CardActions,
        CardContent
    } from 'material-ui/Card';
    import Typography from 'material-ui/Typography';
    
    const styles = {
        container: {
            padding: 16,
        },
        item: {
            background: '#EEE'
        }
    }
    
    class Page extends Component {
        constructor(props) {
            super(props)
            this.state = {}
        }
    
        render() {
            let that = this
    
            let items = []
            for (let i = 0; i < 12; i++) {
                items.push(h(Grid, {
                    item: true,
                    xs: 12,
                    sm: 6,
                    md: 4,
                    lg: 3,
                    style: styles.item,
                }, [
                        h(Card, [
                            h(CardContent, 'Hello Card!')
                        ]),
                    ]))
            }
    
            return h(Grid, {
                container: true,
                spacing: 16,
                style: styles.container,
            }, items)
        }
    }
    
    export default Page
    

    得到效果如下图,手工拉宽浏览器观察不同效果(注意由于截图的原因,看起来卡片变小了,但实际并没有变小):


    xs=12 sm=6 md=4 lg=3

    自动宽度

    我们希望添加左侧导航栏,它固定200像素宽度,右侧内容区自适应充满画面宽度。

    为了让整个页面居中,我们修改index.html中的body:

    <body style="margin: 0;padding: 0;text-align: center">
    

    我们彻底修改一下HomePage的代码:

    • 使用withStyles标准的样式编写格式
    • Style的page设置了最大1000,inline-block让它居中
    • Style的left设置了width:200,
    • render()中的left和right都使用了两层Grid,外层item内层Container
    • return的div使用css.page样式,锁定最大宽度1000像素
    • div内还嵌套了一个Grid容器container,包含了left和right两个Grid(item)
    import {
        Component
    } from 'react'
    import h from 'react-hyperscript'
    import PropTypes from 'prop-types';
    import {
        withStyles
    } from 'material-ui/styles';
    
    import Button from 'material-ui/Button'
    import Grid from 'material-ui/Grid'
    import Card, {
        CardActions,
        CardContent
    } from 'material-ui/Card';
    import Typography from 'material-ui/Typography';
    
    
    const Style = (theme) => ({
        page: {
            maxWidth: 1000,
            width: '100%',
            display: 'inline-block'
        },
        left: {
            background: '#EEE',
            width: 200,
        },
        right: {
            background: '#CCC',
        },
        lfetBtn: {
            width: '100%',
            height: 56
        },
        rightBtn: {
            width: '100%',
            height: 56
        }
    })
    
    class Page extends Component {
        constructor(props) {
            super(props)
            this.state = {}
        }
    
        render() {
            let that = this
            const css = this.props.classes
    
            let rightItems = []
            for (let i = 0; i < 12; i++) {
                rightItems.push(h(Grid, {
                    item: true,
                    xs: 12,
                    sm: 6,
                    md: 4,
                    lg: 3,
                }, [
                    h(Button, {
                        className: css.rightBtn,
                    }, 'hello!'),
                ]))
            }
    
            let leftItems = []
            for (let i = 0; i < 4; i++) {
                leftItems.push(h(Grid, {
                    item: true,
                    xs: 12,
                }, [
                    h(Button, {
                        className: css.lfetBtn,
                    }, 'Nav!'),
                ]))
            }
    
            let right = h(Grid, {
                item: true,
                xs: 12,
                sm: 8,
                className: css.right,
            }, h(Grid, {
                container: true,
            }, rightItems))
    
    
            let left = h(Grid, {
                item: true,
                className: css.left,
            }, h(Grid, {
                container: true,
            }, leftItems))
    
            return h('div', {
                className: css.page,
            }, [
                h(Grid, {
                    container: true,
                    justify: 'center',
                }, [
                    left,
                    right,
                ])
            ])
        }
    }
    
    Page.propTypes = {
        classes: PropTypes.object.isRequired,
    }
    export default withStyles(Style)(Page)
    

    显示效果如下图,无论如何改变窗口宽度,左侧被锁定为200像素不变,右侧自动盛满。


    自动尺寸

    响应式显示和隐藏

    对于上面的布局,当窗口超小xs的时候,left和right会变为竖向排列,看起来很糟糕。

    我们可以让left在xs的时候自动隐藏,然后让一个同样功能的菜单自动出现。

    首先我们需要导入Hidden元素。

    import Hidden from 'material-ui/Hidden';
    

    然后再把最后的left罩一层Hidden,设定only='xs',就是在极小窗口隐藏。
    同样,我们创建一个top,它也是一个container嵌套item的grid结构,外层设定了justify: 'flex-end',alignItems: 'center'这是右对齐上下居中,我们设定了右侧的Button元素所在grid宽度100锁定,左侧div所在grid自动调整。

    修改后的全部代码如下,重点注意底部render()方法:

    import {
        Component
    } from 'react'
    import h from 'react-hyperscript'
    import PropTypes from 'prop-types'
    import {
        withStyles
    } from 'material-ui/styles'
    
    import Button from 'material-ui/Button'
    import Grid from 'material-ui/Grid'
    import Card, {
        CardActions,
        CardContent
    } from 'material-ui/Card';
    import Typography from 'material-ui/Typography';
    import Hidden from 'material-ui/Hidden';
    
    import Icon from 'material-ui/Icon';
    import IconButton from 'material-ui/IconButton';
    import MenuIcon from '@material-ui/icons/Menu';
    
    
    const Style = (theme) => ({
        page: {
            maxWidth: 1000,
            width: '100%',
            display: 'inline-block'
        },
        left: {
            background: '#EEE',
            width: 200,
        },
        right: {
            background: '#CCC',
        },
        menuBtn: {
            width: '100%',
            height: 56
        },
        lfetBtn: {
            width: '100%',
            height: 56
        },
        rightBtn: {
            width: '100%',
            height: 56
        }
    })
    
    class Page extends Component {
        constructor(props) {
            super(props)
            this.state = {}
        }
    
        render() {
            let that = this
            const css = this.props.classes
    
            let rightItems = []
            for (let i = 0; i < 12; i++) {
                rightItems.push(h(Grid, {
                    item: true,
                    xs: 12,
                    sm: 6,
                    md: 4,
                    lg: 3,
                }, [
                    h(Button, {
                        className: css.rightBtn,
                    }, 'hello!'),
                ]))
            }
    
            let leftItems = []
            for (let i = 0; i < 4; i++) {
                leftItems.push(h(Grid, {
                    item: true,
                    xs: 12,
                }, [
                    h(Button, {
                        className: css.lfetBtn,
                    }, 'Nav!'),
                ]))
            }
    
            let right = h(Grid, {
                item: true,
                xs: 12,
                sm: 8,
                className: css.right,
            }, h(Grid, {
                container: true,
            }, rightItems))
    
    
            let left = h(Grid, {
                item: true,
                className: css.left,
            }, h(Grid, {
                container: true,
            }, leftItems))
    
            let top = h(Grid, {
                container: true,
                justify: 'flex-end',
                alignItems: 'center'
            }, [
                h(Grid, {
                    item: true,
                    xs: 8,
                }, h('div', '')),
                h(Grid, {
                    item: true,
                    style: {
                        width: 100
                    }
                }, h(Button, {
                    className: css.menuBtn,
                }, h(MenuIcon)))
            ])
    
            return h('div', {
                className: css.page,
            }, [
                h(Grid, {
                    container: true,
                    justify: 'center',
                }, [
                    h(Hidden, {
                        only: ['sm', 'md', 'lg', 'xl']
                    }, top),
                    h(Hidden, {
                        only: ['xs']
                    }, left),
    
                    right,
                ])
            ])
        }
    }
    
    Page.propTypes = {
        classes: PropTypes.object.isRequired,
    }
    export default withStyles(Style)(Page)
    

    实际效果是当窗口宽度达到xs的时候,顶部按钮就会自动显示出来。


    自动显示和隐藏

    此外,还有一些其他解决方案实现隐藏和显示,参考官方的Grid案例

    菜单按钮可以点击,但还不能弹出内容,可以参照这里的官方文档创建


    致力于让一切变得简单

    如果您发现文章错误,请不吝留言指正;
    如果您觉得有用,请点喜欢;
    如果您觉得很有用,欢迎转载~


    END

    相关文章

      网友评论

        本文标题:Material-UI-React-Layout-响应式布局

        本文链接:https://www.haomeiwen.com/subject/sxfwrftx.html