Material-UI-React-Electron-项目文件结构

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

继续上一篇React+Electron项目快速搭建,这篇介绍如何在React下使用MaterialUI界面框架,实现谷歌MaterialDesign界面设计风格。

MaterialUI官方网站


安装MaterialUI

cnpm install material-ui@next --save-dev
cnpm install @material-ui/icons --save-dev

这里@next使用了最新的版本,也可以去掉就会使用稳定版。


测试MaterialUI

修改index.js,创建一个MD按钮元素,点击可以产生漂亮的水波效果。

import React from 'react';
import ReactDOM from 'react-dom';
import h from 'react-hyperscript';

import Button from 'material-ui/Button';

function App() {
    return h(Button, {
        variant: 'raised',
        color: 'primary',
        children:'BUTTON',
    })
}

ReactDOM.render(h(App), document.getElementById('root'));

这里使用了hyperscript语法格式h(tagname,attrsObj),相当于创建了一个DOM
<Button variant="raised" color="primary">BUTTON</Button>

关于Button的更多设置,请参考官方文档


组织页面文件结构

我们把整个整个站点分为四层:

  1. APP应用层,提供一些全站通用功能,控制整个界面,它负责载入页面和切换页面。相当于简单的路由功能。
  2. Pages页面层,实现不同的页面,它负责把页面划分成不同的区块(如顶部导航栏+主体内容区或左侧导航栏+主题内容区+右侧功能区),并且管理各个区块的切换和显示,同时为下一层各个单元之间通信实现接口。跨区块的业务逻辑在这里实现。
  3. Blocks区块层,实现每个区块的独立布局和相应功能,能够接收上级页面层传来的参数并作出相应。主要的业务逻辑都在这里实现。
  4. Units单元层,区块层的更小的界面单位。实现更加细节的业务功能。
  5. Symbols元件层,只实现UI样式和动画交互等,不实现业务逻辑。(这里主要使用MaterialUI的组件)
  6. Utilities工具组,一些通用函数,非界面相关,但可以在任意层级中调用这些工具。

基于以上思路,我们在src下分别创建五个文件夹App、Pages、Blocks、Units、Symbols、Utilities。(brackets是按照文件夹名称排列的,顺序并不代表层级)


实现App应用层

修改src/index.js文件,使它读取并显示src/App/App.js生成的内容:

import React from 'react'
import ReactDOM from 'react-dom'
import h from 'react-hyperscript'

import App from './App/App'

ReactDOM.render(h(App), document.getElementById('root'))

新建src/App/App.js文件,暂时仅生成最简单的文字:

import {
    Component
} from 'react'
import h from 'react-hyperscript'

class App extends Component {
    render() {
        return h('h1', 'Hello MaterialUI!')
    }
}
export default App

顺利的话这时候页面已经自动刷新显示了Hello MaterialUI!文字。

更多关于React的component组件的创建请参考官方文档,官方标准使用的是JSX语法,而我的文章中改为使用hyperscript就是大家在这里一直看到的h(tagNameOrComponent,attrObj,[children])方法


实现Page页面层

首先创建一个欢迎页文件src/Pages/WelcomePage/WelcomePage.js,内容如下:

import {
    Component
} from 'react'
import h from 'react-hyperscript'

class WelcomePage extends Component {
    render() {
        return h('h1','Welcome to my website!')
    }
}

export default WelcomePage

然后我们创建一个设置文件,用于管理全部页面,src/App/_pages.js内容如下:

import WelcomePage from '../Pages/WelcomePage/WelcomePage'
const pages = {
    WelcomePage,
}

export default pages

最后,我们修改一下App.js,调用页面设置,并显示Welcome页面。

import {
    Component
} from 'react'
import h from 'react-hyperscript'
import Pages from './_pages'

class App extends Component {
    constructor(props) {
        super(props)
        this.state = {
            curPage: Pages.WelcomePage,
        }
    }

    render() {
        let that = this
        return h(that.state.curPage)
    }
}

export default App

在这里使用了constructor方法来初始化class类,创建了state状态对象用来管理界面上的各种不同状态属性。

这时候浏览器内显示了欢迎页:


Block区块层和Units单元层、Symbols元件层的实现原理与这个类似,Utilities工具层是不同的。在后面的文章中会逐步介绍。


增加自定义CSS样式

我们可以创建自己的CSS样式,然后引入到App、Page或其他元素中,这里以App为例。

首先创建文件src/App/_styles.js。注意,我们使用js(而不是css)来更加自由的创建css样式类。

const styles = theme => ({
    app: {
        background:'#FAFAFA',
        '-webkit-font-smoothing': 'antialiased',
    },
})
export default styles

修改App.js引入这个_style并使用它:

import {
    Component
} from 'react'
import h from 'react-hyperscript'
import {
    MuiThemeProvider,
    withStyles
} from 'material-ui/styles'
import PropTypes from 'prop-types'

import Pages from './_pages'
import Style from './_style'

class App extends Component {
    constructor(props) {
        super(props)
        this.state = {
            curPage: Pages.WelcomePage,
        }
    }

    render() {
        let that = this
        const css = this.props.classes
        
        return h('div', {
            style: {
                marginTop:'100px',
            },
            className:css.app,
        }, [h(that.state.curPage)])
    }
}

App.propTypes = {
    classes: PropTypes.object.isRequired,
}
export default withStyles(Style)(App)

注意开头代码import引入了withStyles和PropTypes两个模块,尾部代码withStyles(Style)(App)把样式style注入到App中。在render()的return部分,我们在curPage外层嵌套了一层div,并使用style给它添加了自定义css样式,并使用了css.app调用了_style.js里面定义的样式类。得到结果如下,可以看到css.app产生的灰色背景,以及直接style产生的marginTop上边距:

再次强调,这个模式不限于App,可以在任何Page、Unit使用。


自定义主题

我们可能需要MaterialUI的默认设置(颜色、圆角、字体大小等)进行一些自定义,这可以在App层方便的设置。

首先我们为Welcome.js增加一个按钮,以便于我们观察效果

import {
    Component
} from 'react'
import h from 'react-hyperscript'

import Button from 'material-ui/Button';

class WelcomePage extends Component {
    render() {
        return h(Button, {
            color: 'primary',
            variant:'raised',
        }, 'Welcome to my website!')
    }
}

export default WelcomePage

默认情况它看起来这样(去掉了上面添加的style效果):

关于Button的更多设置,请参考官方文档

我们在App层创建一个主题src/App/_theme.js,去掉按钮的圆角和阴影:

import { createMuiTheme } from 'material-ui/styles';
import teal from 'material-ui/colors/teal';
import pink from 'material-ui/colors/pink';
import red from 'material-ui/colors/red';

const Theme = createMuiTheme({
    palette: {
        primary: teal,
        accent: pink,
        error: red,
    },
    overrides: {
        MuiButton: {
            root: {
                borderRadius: 0,
                boxShadow: 'none',
            },
            raised: {
                borderRadius: 0,
                boxShadow: 'none',
            },
        },
    },
});

export default Theme;

然后我们在App.js中使用它,将影响全站所有的页面、区块等:

import {
    Component
} from 'react'
import h from 'react-hyperscript'
import {
    MuiThemeProvider,
    withStyles
} from 'material-ui/styles'
import PropTypes from 'prop-types'
import Grid from 'material-ui/Grid';

import Pages from './_pages'
import Style from './_style'
import Theme from './_theme'

class App extends Component {
    constructor(props) {
        super(props)
        this.state = {
            curPage: Pages.WelcomePage,
        }
    }

    render() {
        let that = this
        const css = this.props.classes
        
        return h(MuiThemeProvider, {
            theme: Theme,
        }, h(Grid, {
            container: true,
            spacing: 0,
            className: css.app,
        }, [h(that.state.curPage)]))
    }
}

App.propTypes = {
    classes: PropTypes.object.isRequired,
}
export default withStyles(Style)(App)

这里我们使用了h(MuiThemeProvider)在外层嵌套了主体管理对象,它将对所有内部的页面产生效果。同时我们使用了Grid网格来更容易的实现布局。

请注意到按钮颜色、圆角和阴影的变化。

我们在App文件夹增加了_theme.js,_style.js,_pages.js等设置文件,一般我们还会增加一个_config.js文件用来保存其他更多的统一设定。下面是项目的文件结构:



结语

到这里,我们搭建了最基本的网站结构文件结构,并引入了界面解决方案。可以说,对于一个前端站点架构,我们已经完成了一半。

另一半就是,在安心写代码之前,我们还需要实现各个页面的跳转、各个区块的状态切换管理等复杂的控制,以及页面之间、区块之间、页面和区块之间、甚至单元和区块之间的数据传递。

不用担心,我们后面的文章中会以最简单的方式实现这些:路由和数据穿越。


致力于让一切变得通俗易懂

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


END

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,038评论 25 707
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,747评论 1 92
  • Sayings: 今天故事里这几个人,是在“追到一个人”这件事上,最专业的一群。 因为电视剧《猎场》,身边人会谈论...
    新世相阅读 837评论 0 13
  • 本人从零八年开始用手机拍照,云盘上备份了40T的图片和视频,大约有十万多张照片,之前有个卡片机是八百万像素,...
    这个名字取的好阅读 992评论 7 7
  • 本文参加「世界华语悬疑文学大赛」征文活动,本人承诺,作品为原创。 第一节 晚上八点半敲开猫咪的门,却发现猫咪并未坐...
    半江灰阅读 404评论 0 0