├── favicon.ico
├── jsconfig.json
├── public
├── favicon.ico
├── manifest.json
└── index.html
├── src
├── assist
│ ├── images
│ │ └── loading.gif
│ └── styles
│ │ ├── layout.scss
│ │ ├── about.scss
│ │ ├── items.scss
│ │ ├── variables.scss
│ │ ├── reset.scss
│ │ └── main.scss
├── store
│ ├── index.js
│ ├── home.js
│ ├── detail.js
│ └── items.js
├── utils
│ ├── objectEmpty.js
│ └── getDate.js
├── compontens
│ ├── common
│ │ ├── footer.js
│ │ └── header.js
│ ├── App.js
│ ├── home.js
│ ├── detail.js
│ ├── about.js
│ └── itemsList.js
├── config
│ └── config.js
├── index.js
├── routers
│ └── index.js
└── registerServiceWorker.js
├── .travis.yml
├── .idea
├── vcs.xml
├── vagrant.xml
└── codeStyleSettings.xml
├── config
├── jest
│ ├── fileTransform.js
│ └── cssTransform.js
├── polyfills.js
├── paths.js
├── env.js
├── webpackDevServer.config.js
├── webpack.config.dev.js
└── webpack.config.prod.js
├── manifest.json
├── .gitignore
├── scripts
├── test.js
├── start.js
└── build.js
├── LICENSE
├── package.json
├── index.html
├── README-zh.md
└── README.md
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hancoson/react-mobx-demo/HEAD/favicon.ico
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "experimentalDecorators": true
4 | }
5 | }
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hancoson/react-mobx-demo/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assist/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hancoson/react-mobx-demo/HEAD/src/assist/images/loading.gif
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "6"
4 | after_success:
5 | - bash <(curl -s https://codecov.io/bash)
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vagrant.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-07 15:43:32
4 | * @version 0.0.1
5 | */
6 | import {homeStore} from './home'
7 | import {itemsStore} from './items'
8 | import {detailStore} from './detail'
9 |
10 | export {homeStore, itemsStore, detailStore}
--------------------------------------------------------------------------------
/src/utils/objectEmpty.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-08 17:27:43
4 | * @version 0.0.1
5 | */
6 |
7 | export const isEmptyObject = obj => {
8 | for (var key in obj) {
9 | if (obj.hasOwnProperty(key)) {
10 | return false;
11 | }
12 | }
13 | return true;
14 | }
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | // This is a custom Jest transformer turning file imports into filenames.
6 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
7 |
8 | module.exports = {
9 | process(src, filename) {
10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`;
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/src/compontens/common/footer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-08 17:24:24
4 | * @version 0.0.1
5 | */
6 |
7 | import React, { Component } from 'react'
8 | export default class Footer extends Component {
9 |
10 | render() {
11 | return (
12 |
16 | )
17 | }
18 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | # /build
11 | /build/manifest.json
12 |
13 | # misc
14 | .idea
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | #styles
26 | /src/assist/styles/*.css
27 |
--------------------------------------------------------------------------------
/src/config/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-11 16:53:56
4 | * @version 0.0.1
5 | */
6 | export default {
7 | URL_PREFIX : 'http://daily.zhihu.com/story/',
8 | API : 'http://news-at.zhihu.com/api/4/news/before/',//消息列表
9 | NEWS : 'http://news-at.zhihu.com/api/4/news/',//消息内容获取
10 | YAHOO : 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20json%20where%20url=%22',
11 | YAHOO_SUFFIX: '%22&format=json'
12 | };
--------------------------------------------------------------------------------
/src/store/home.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-07 15:46:16
4 | * @version 0.0.1
5 | */
6 | import {observable, action} from 'mobx';
7 |
8 | class HomeStore {
9 | @observable text;
10 | @observable num;
11 |
12 | constructor() {
13 | this.num = 0
14 | this.text = 'Hello Word!'
15 | }
16 |
17 | @action plus = () => {
18 | this.num = ++this.num
19 | }
20 | @action minus = () => {
21 | this.num = --this.num
22 | }
23 | }
24 |
25 | const homeStore = new HomeStore()
26 |
27 | export {homeStore}
--------------------------------------------------------------------------------
/src/assist/styles/layout.scss:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Guoxing.Han(hancoson#163.com)
4 | * @time 2016/11/14.
5 | */
6 | @import 'variables.scss';
7 | body{
8 | }
9 | .main{
10 | width: 1200px;
11 | position: relative;
12 | margin: 0 auto;
13 | }
14 | section{
15 | @extend .border-box;
16 | width: 100%;
17 | margin-top: 40px;
18 | }
19 |
20 |
21 | .index-warp{
22 | text-align: center;
23 | padding: 100px 0
24 | }
25 |
26 |
27 | footer{
28 | width: 100%;
29 | text-align: center;
30 | padding: 20px 0;
31 | color: #999;
32 | font-size: 13px;
33 | background: #fff;
34 | border-top:#f0f0f0 1px solid;
35 | margin-top: 20px;
36 | }
37 |
38 | .loading{
39 | margin: 100px auto;
40 | text-align: center;
41 | }
42 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-25 17:23:43
4 | * @version 0.0.1
5 | */
6 | import React from 'react';
7 | import ReactDOM from 'react-dom';
8 | import {useStrict} from 'mobx';
9 | import {HashRouter as Router} from 'react-router-dom'
10 | import {Provider} from 'mobx-react';
11 | import * as stores from './store';
12 |
13 | import App from './compontens/App'
14 |
15 | import './assist/styles/main.css';
16 | import registerServiceWorker from './registerServiceWorker';
17 |
18 | useStrict(true) // 不允许在动作之外进行状态修改
19 |
20 | ReactDOM.render(
21 |
22 |
23 |
24 |
25 | , document.getElementById('root'));
26 | registerServiceWorker();
27 |
--------------------------------------------------------------------------------
/src/compontens/App.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-08 17:24:43
4 | * @version 0.0.1
5 | */
6 | import React, {Component} from 'react'
7 | import {observer, inject} from 'mobx-react'
8 | import {withRouter} from 'react-router-dom'
9 | //import DevTools from 'mobx-react-devtools';
10 |
11 | import Main from './../routers';
12 |
13 | import Header from './common/header'
14 | import Footer from './common/footer'
15 |
16 | @withRouter @inject('store') @observer
17 | class App extends Component {
18 |
19 | render() {
20 | return (
21 |
22 |
23 |
24 |
25 |
26 |
27 | {/* */}
28 |
29 | )
30 | }
31 | }
32 |
33 | export default App
--------------------------------------------------------------------------------
/src/routers/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-08 17:26:17
4 | * @version 0.0.1
5 | */
6 | import React from 'react'
7 | import {Route, Switch} from 'react-router-dom'
8 |
9 | import Index from './../compontens/home'
10 | import About from './../compontens/about'
11 | import Items from './../compontens/itemsList'
12 | import Detail from './../compontens/detail'
13 |
14 | const Main = () => (
15 |
16 | ( )}/>
17 |
18 | ( )}/>
19 | ( )}/>
20 | 找不到此页面 }/>
21 |
22 | )
23 |
24 | export default Main;
--------------------------------------------------------------------------------
/scripts/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Do this as the first thing so that any code reading it knows the right env.
4 | process.env.BABEL_ENV = 'test';
5 | process.env.NODE_ENV = 'test';
6 | process.env.PUBLIC_URL = '';
7 |
8 | // Makes the script crash on unhandled rejections instead of silently
9 | // ignoring them. In the future, promise rejections that are not handled will
10 | // terminate the Node.js process with a non-zero exit code.
11 | process.on('unhandledRejection', err => {
12 | throw err;
13 | });
14 |
15 | // Ensure environment variables are read.
16 | require('../config/env');
17 |
18 | const jest = require('jest');
19 | const argv = process.argv.slice(2);
20 |
21 | // Watch unless on CI or in coverage mode
22 | if (!process.env.CI && argv.indexOf('--coverage') < 0) {
23 | argv.push('--watch');
24 | }
25 |
26 |
27 | jest.run(argv);
28 |
--------------------------------------------------------------------------------
/src/store/detail.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Guoxing.Han(hancoson#163.com)
3 | * @time 2017/12/13
4 | */
5 | import {observable, action} from 'mobx'
6 | import Config from './../config/config'
7 |
8 | class DetailStore {
9 | @observable detail
10 |
11 | constructor() {
12 | this.detail = {}
13 | }
14 |
15 | @action emptyData=()=>{
16 | this.detail = {}
17 | }
18 |
19 | @action fetchDetailData = (id) => {
20 | fetch(Config.YAHOO + Config.NEWS + id + Config.YAHOO_SUFFIX).then(
21 | action('fetchRes', res => {
22 | return res.json()
23 | })).then(
24 | action('fetchSuccess', data => {
25 | this.detail = data.query.results.json;
26 | })).catch(
27 | action('fetchError', e => {
28 | console.log(e.message)
29 | }))
30 | }
31 |
32 | }
33 |
34 | const detailStore = new DetailStore()
35 | export {detailStore}
36 |
--------------------------------------------------------------------------------
/src/utils/getDate.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-08 17:27:28
4 | * @version 0.0.1
5 | */
6 |
7 | //获取当天时间并格式化
8 | export const getDate = () => {
9 | let d = new Date();
10 | let m = d.getMonth() + 1;
11 | let dd = d.getDate();
12 | if (m < 10) {
13 | m = '0' + m.toString()
14 | }
15 | if (dd < 10) {
16 | dd = '0' + dd.toString()
17 | }
18 | let str = d
19 | .getFullYear()
20 | .toString() + m + dd.toString();
21 | return str
22 | }
23 |
24 | //格式化时间
25 | export const subString = str => {
26 | let _y = '',
27 | _m = '',
28 | _d = '';
29 | _y = str.substring(0, 4);
30 | _m = str.substring(4, 6);
31 | _d = str.substring(6, 8);
32 | return (_y + '/' + _m + '/' + _d)
33 |
34 | }
35 | //格式化时间
36 | export const timeClear = str => {
37 | let _t = '';
38 | str
39 | .split('-')
40 | .forEach((i) => {
41 | _t = _t + i.toString()
42 | })
43 | return _t
44 |
45 | }
--------------------------------------------------------------------------------
/config/polyfills.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | if (typeof Promise === 'undefined') {
4 | // Rejection tracking prevents a common issue where React gets into an
5 | // inconsistent state due to an error, but it gets swallowed by a Promise,
6 | // and the user has no idea what causes React's erratic future behavior.
7 | require('promise/lib/rejection-tracking').enable();
8 | window.Promise = require('promise/lib/es6-extensions.js');
9 | }
10 |
11 | // fetch() polyfill for making API calls.
12 | require('whatwg-fetch');
13 |
14 | // Object.assign() is commonly used with React.
15 | // It will use the native implementation if it's present and isn't buggy.
16 | Object.assign = require('object-assign');
17 |
18 | // In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet.
19 | // We don't polyfill it in the browser--this is user's responsibility.
20 | if (process.env.NODE_ENV === 'test') {
21 | require('raf').polyfill(global);
22 | }
23 |
--------------------------------------------------------------------------------
/src/assist/styles/about.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Guoxing.Han(hancoson#163.com)
3 | * @time 2017/1/13.
4 | */
5 | .about-warp {
6 | h1 {
7 | padding-bottom: 5px;
8 | border-bottom: 1px #f0f0f0 solid;
9 | font-size: 32px;
10 | margin-bottom: 20px;
11 | }
12 | ul {
13 | padding-left: 20px;
14 | li {
15 | line-height: 1.6;
16 | list-style: circle;
17 | }
18 | }
19 | h2 {
20 | font-size: 26px;
21 | }
22 | code{
23 | padding: 2px 4px;
24 | font-size: 90%;
25 | color: #c7254e;
26 | background-color: #f9f2f4;
27 | border-radius: 4px;
28 | font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
29 | }
30 | pre{
31 | display: block;
32 | padding: 9.5px;
33 | margin: 0 0 10px;
34 | font-size: 13px;
35 | line-height: 1.42857143;
36 | color: #333;
37 | word-break: break-all;
38 | word-wrap: break-word;
39 | background-color: #f5f5f5;
40 | border: 1px solid #ccc;
41 | border-radius: 4px;
42 | }
43 | }
--------------------------------------------------------------------------------
/src/assist/styles/items.scss:
--------------------------------------------------------------------------------
1 | .items-warp {
2 | width: 100%;
3 | margin-top: 10px;
4 | .bar {
5 | width: 100%;
6 | background: #f7f7f7;
7 | padding: 10px;
8 | }
9 | .gutter-example .ant-row > div {
10 | border: 0;
11 | }
12 | .gutter-box {
13 | background: #00A0E9;
14 | padding: 5px 0;
15 | }
16 | .item {
17 | display: block;
18 | padding: 10px;
19 | height: 100px;
20 | position: relative;
21 | background: #f5f5f5;
22 | border-radius: 10px;
23 | margin: 10px 0 10px;
24 | transition: all .2s linear 0s;
25 | &:hover{
26 | box-shadow: 0 5px 10px rgba(0,0,0,.1);
27 | }
28 | img{
29 | display: block;
30 | width: 80px;
31 | height: 80px;
32 | float: left;
33 | margin-right: 10px;
34 | }
35 | p{
36 | font-size: 14px;
37 | line-height: 1.4;
38 | color: #31b9ff;
39 | }
40 | sub{
41 | font-size: 13px;
42 | position: absolute;
43 | bottom: 13px;
44 | right: 13px;
45 | color: #999;
46 | }
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/src/compontens/home.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-08 17:25:00
4 | * @version 0.0.1
5 | */
6 | import React, {Component} from 'react'
7 | import {inject, observer} from "mobx-react";
8 |
9 | @inject("store") @observer
10 | export default class Index extends Component {
11 | constructor(props) {
12 | super(props)
13 | this.store = props.store.homeStore
14 | this.plus = this.store.plus
15 | this.minus = this.store.minus
16 | }
17 |
18 | render() {
19 | const {text,num} = this.store
20 | return (
21 |
22 |
{text}
23 |
24 | -
25 | {num}
26 | +
27 |
28 |
29 | )
30 | }
31 |
32 | plusHandle() {
33 | this.plus()
34 | }
35 | minusHandle() {
36 | this.minus()
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Hancoson(hancoson#163.com)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/compontens/detail.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-08 17:24:52
4 | * @version 0.0.1
5 | */
6 | import React, { Component } from 'react'
7 | import { Spin } from 'antd';
8 | import { isEmptyObject } from './../utils/objectEmpty'
9 | import {inject, observer} from "mobx-react";
10 |
11 | @inject("store") @observer
12 | export default class Detail extends Component {
13 | constructor(props){
14 | super(props)
15 | this._id = props.match.params.id
16 | this.store = props.store.detailStore
17 | }
18 | componentWillMount() {
19 | const { fetchDetailData, emptyData } = this.store;
20 | //调取数据
21 | fetchDetailData(this._id)
22 | //清空原有的数据
23 | emptyData()
24 | }
25 |
26 | createMarkup() {
27 | var _fonts = this.store.detail.body;
28 | return { __html: _fonts };
29 | }
30 |
31 | render() {
32 | const _o = this.store.detail;
33 |
34 | return (
35 |
36 | {
37 | isEmptyObject(_o) ?
38 |
39 |
40 |
:
41 |
42 | }
43 |
44 |
45 | )
46 | }
47 | }
--------------------------------------------------------------------------------
/src/store/items.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-11 16:48:57
4 | * @version 0.0.1
5 | */
6 | import {observable, action, computed, autorun} from 'mobx';
7 |
8 | import Config from './../config/config'
9 | import {getDate, subString, timeClear} from './../utils/getDate'
10 |
11 | class ItemsStore {
12 | @observable items;
13 | @observable dataTime;
14 |
15 | constructor() {
16 | this.items = []
17 | this.dataTime = ''
18 | }
19 |
20 | @computed get total() {
21 | return this.items.length;
22 | }
23 |
24 | @action
25 | fetchData = (time) => {
26 | fetch(Config.YAHOO + Config.API + time + Config.YAHOO_SUFFIX).then(
27 |
28 | action('fetchRes', res => {
29 | return res.json()
30 | })).then(
31 |
32 | action('fetchSuccess', data => {
33 | this.items = data.query.results.json.stories;
34 | this.dataTime = data.query.results.json.date;
35 |
36 | })).catch(
37 |
38 | action('fetchError', e => {
39 | console.log(e.message)
40 | }))
41 | }
42 |
43 | @action
44 | emptyData = () => {
45 | this.items = []
46 | }
47 |
48 | defaultDate = autorun((e) => this.fetchData(getDate()))
49 | }
50 |
51 | const itemsStore = new ItemsStore()
52 |
53 | export {itemsStore}
--------------------------------------------------------------------------------
/src/compontens/common/header.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-08 17:24:11
4 | * @version 0.0.1
5 | */
6 | import React, {Component} from 'react'
7 | import {Link} from 'react-router-dom'
8 | import {Menu} from 'antd';
9 |
10 | export default class Header extends Component {
11 | constructor(porps) {
12 | super(porps);
13 |
14 | this.state = {
15 | current: this.props.pathname === '/'
16 | ? '/index'
17 | : this.props.pathname
18 | }
19 | }
20 |
21 | handleClick(e) {
22 | if(e.key !== this.state.current)
23 | this.setState({current: e.key});
24 | }
25 |
26 | render() {
27 | return (
28 |
34 |
35 |
36 | 首页
37 |
38 |
39 |
40 |
41 | 文章
42 |
43 |
44 |
45 |
46 | 关于
47 |
48 |
49 |
50 | )
51 | }
52 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-mobx-demo",
3 | "version": "1.0.0",
4 | "description": "Get started with React, Mobx, and React-Router to achieve a Zhihu Daily App.",
5 | "author": "Hancoson (http://github.com/hancoson)",
6 | "license": "MIT",
7 | "private": true,
8 | "dependencies": {
9 | "antd": "^2.0.0",
10 | "mobx": "^2.5.0",
11 | "mobx-react": "^3.5.5",
12 | "mobx-react-devtools": "^4.2.5",
13 | "mobx-react-router": "^4.0.1",
14 | "react": "^15.3.1",
15 | "react-dom": "^15.3.1",
16 | "react-router-dom": "^4.2.2"
17 | },
18 | "scripts": {
19 | "build-css": "node-sass-chokidar src/ -o src/",
20 | "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
21 | "start-js": "react-scripts start",
22 | "start": "npm-run-all -p watch-css start-js",
23 | "build-js": "react-scripts build",
24 | "build": "npm-run-all build-css build-js",
25 | "test": "react-scripts test --env=jsdom",
26 | "eject": "react-scripts eject",
27 | "clean": "yarn cache clean && rm -rf node_modules && rm -rf yarn.lock && yarn"
28 | },
29 | "devDependencies": {
30 | "babel-plugin-transform-decorators-legacy": "^1.3.4",
31 | "babel-preset-stage-2": "^6.24.1",
32 | "node-sass-chokidar": "^0.0.3",
33 | "npm-run-all": "^4.1.2",
34 | "react-scripts": "0.2.3"
35 | }
36 | }
--------------------------------------------------------------------------------
/src/assist/styles/variables.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * 变量
3 | * @author 墨萧
4 | * @time 2016/06/06
5 | * @version 0.1.0
6 | */
7 |
8 |
9 | /**
10 | * 继承代码
11 | **/
12 |
13 | //border-box
14 | .border-box {
15 | -moz-box-sizing: border-box;
16 | -webkit-box-sizing: border-box;
17 | -o-box-sizing: border-box;
18 | -ms-box-sizing: border-box;
19 | box-sizing: border-box;
20 | }
21 |
22 | //旋转360
23 | .transition {
24 | -moz-transition: -moz-transform 0.3s ease;
25 | -webkit-transition: -webkit-transform 0.3s ease;
26 | transition: transform 0.3s ease;
27 | }
28 |
29 | //截取长度显示省略号
30 | .ellipsis {
31 | overflow: hidden;
32 | text-overflow: ellipsis;
33 | white-space: nowrap;
34 | }
35 |
36 | //滚动条
37 | .scrollbar::-webkit-scrollbar-track {
38 | -webkit-box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.2);
39 | border-radius: 6px;
40 | background-color: #F5F5F5;
41 | }
42 |
43 | .scrollbar::-webkit-scrollbar {
44 | width: 3px;
45 | background-color: #fff;
46 | }
47 |
48 | .scrollbar::-webkit-scrollbar-thumb {
49 | border-radius: 6px;
50 | -webkit-box-shadow: inset 0 0 1px rgba(0, 0, 0, .2);
51 | background-color: #07a1d6;
52 | }
53 |
54 |
55 | /**
56 | * flex
57 | **/
58 |
59 | .flex {
60 | display: -webkit-box;
61 | display: -webkit-flex;
62 | display: -ms-flexbox;
63 | display: flex;
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/src/compontens/about.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @Author: Guoxing.han
3 | * @Date: 2017-12-08 17:24:32
4 | * @version 0.0.1
5 | */
6 | import React, { Component } from 'react'
7 |
8 | export default class About extends Component {
9 |
10 | render() {
11 |
12 | return (
13 |
14 |
15 | React-Mobx Zhihu Daily
16 |
17 | 一个React+Mobx版知乎日报 所有API均来自网络(若涉及侵权,请及时联系我删除)
18 | Github [https://github.com/Hancoson/react-mobx-demo]
19 |
20 |
21 |
22 | 技术实现
23 |
24 | 采用creat-react-app构建生成脚手架
25 | 采用React+mobx+React-router(v4)+antd等实现
26 |
27 |
28 |
29 | 运行
30 |
31 | 安装 npm install(yarn)
32 | 启动 npm start
33 | 构建 npm build
34 |
35 |
36 |
37 | 目录结构
38 |
39 | ├─src
40 | │ ├─assets //静态资源
41 | │ │ ├─img
42 | │ │ └─scss
43 | │ ├─compontens //组建
44 | │ ├─config
45 | │ ├─routes //路由
46 | │ ├─store //store
47 | │ └─utils //工具函数
48 | └─build //发布目录
49 |
50 |
51 |
52 | )
53 | }
54 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | react-mobx|知乎日报
8 |
9 |
10 |
14 |
15 |
16 |
25 |
26 |
27 |
28 | You need to enable JavaScript to run this app.
29 |
30 |
31 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | react-mobx|知乎日报
8 |
9 |
10 |
14 |
15 |
16 |
25 | React App
26 |
27 |
28 |
29 | You need to enable JavaScript to run this app.
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/assist/styles/reset.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * reset
3 | * @author 墨萧
4 | * @time 2016/06/06
5 | * @version 0.1.0
6 | */
7 | html, body, div, span, applet, object, iframe,
8 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
9 | a, abbr, acronym, address, big, cite, code,
10 | del, dfn, em, img, ins, kbd, q, s, samp,
11 | small, strike, strong, sub, sup, tt, var,
12 | b, u, i, center,
13 | dl, dt, dd, ol, ul, li,
14 | fieldset, form, label, legend,
15 | table, caption, tbody, tfoot, thead, tr, th, td,
16 | article, aside, canvas, details, embed,
17 | figure, figcaption, footer, header,
18 | menu, nav, output, ruby, section, summary,
19 | time, mark, audio, video {
20 | margin: 0;
21 | padding: 0;
22 | border: 0;
23 | font: inherit;
24 | }
25 |
26 | * {
27 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
28 | }
29 |
30 | /* HTML5 display-role reset for older browsers */
31 | article, aside, details, figcaption, figure,
32 | footer, header, menu, nav, section {
33 | display: block;
34 | }
35 |
36 | body {
37 | line-height: 1;
38 | font-family: sans-serif;
39 | }
40 |
41 | ol, ul, ul li {
42 | list-style: none;
43 | }
44 |
45 | blockquote, q {
46 | quotes: none;
47 | }
48 |
49 | blockquote:before, blockquote:after,
50 | q:before, q:after {
51 | content: '';
52 | content: none;
53 | }
54 |
55 | table {
56 | border-collapse: collapse;
57 | border-spacing: 0;
58 | }
59 |
60 | input {
61 | outline: 0;
62 | }
63 |
64 | input, textarea, keygen, select, button {
65 | font: inherit;
66 | &:focus {
67 | outline: none;
68 | }
69 | }
70 |
71 | button, a {
72 | border: 0;
73 | cursor: pointer;
74 | }
75 |
76 | a, a:hover {
77 | text-decoration: none;
78 | }
79 |
80 | .clearfix:before,
81 | .clearfix:after {
82 | display: table;
83 | content: " ";
84 | }
85 |
86 | .clearfix:after {
87 | clear: both;
88 | }
89 |
90 | /* End hide from IE-mac */
91 | .no-scroll {
92 | overflow: hidden;
93 | position: relative;
94 | }
95 |
96 | .fl {
97 | float: left;
98 | }
99 |
100 | .fr {
101 | float: right;
102 | }
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const url = require('url');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebookincubator/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | const envPublicUrl = process.env.PUBLIC_URL;
13 |
14 | function ensureSlash(path, needsSlash) {
15 | const hasSlash = path.endsWith('/');
16 | if (hasSlash && !needsSlash) {
17 | return path.substr(path, path.length - 1);
18 | } else if (!hasSlash && needsSlash) {
19 | return `${path}/`;
20 | } else {
21 | return path;
22 | }
23 | }
24 |
25 | const getPublicUrl = appPackageJson =>
26 | envPublicUrl || require(appPackageJson).homepage;
27 |
28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
29 | // "public path" at which the app is served.
30 | // Webpack needs to know it to put the right