美文网首页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-响应式布局

    React+Electron桌面应用开发文章索引 继续前面的文章,这篇文章介绍基于MaterialUI的响应式布局...

  • 响应式布局目录

    └─Web响应式布局├─1 响应式布局介绍├─2 响应式布局实例(Media Queries模块) 上├─3 响应...

  • 九、HTML5响应式布局

    @(HTML5)[相应式布局] [TOC] 九、HTML5响应式布局 什么是响应式网页设计(布局) 响应式网页设计...

  • 响应式网页开发

    响应式布局 什么是响应式布局?可以让一个网站兼容不同分辨率设备的布局 为什么要使用响应式布局?给用户更好的视觉使用...

  • 响应式开发

    响应式布局 什么是响应式布局?可以让一个网站兼容不同分辨率设备的布局 为什么要使用响应式布局?给用户更好的视觉使用...

  • js基础(6)

    27、移动端响应式布局开发 响应式布局开发 1、什么是响应式布局开发?把我们开发完成的产品,能够让其适配不同的设备...

  • flex布局及常用属性

    flex 布局 demo 圣杯响应式布局

  • VUE响应式原理

    VUE响应式原理 这里的响应式(Reactive)不同于CSS布局的响应式(Responsive), 这里的响应式...

  • 响应式布局与自适应布局

    前言 这几天工作的时候被提出需要响应式布局的需求,但是响应式布局和自适应布局有嗲傻傻分不清楚。所以响应式布局和自适...

  • bootstrap系列之响应式布局及相关的visible-sm、

    响应式布局:响应式工具不能用于table元素,而且 本身就不支持 响应式布局需要在处添加如下语句: 在...

网友评论

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

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