├── .babelrc ├── .gitignore ├── app ├── action.js ├── components │ ├── about.jsx │ ├── basic.jsx │ ├── home.jsx │ ├── test.jsx │ └── topics.jsx ├── main.js └── reducer.js ├── build ├── bundle.js └── index.html ├── package.json ├── readme.md └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | //.babelrc 2 | { 3 | "presets": [ 4 | "react", 5 | "es2015" 6 | ] 7 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /app/action.js: -------------------------------------------------------------------------------- 1 | export function increaseAction() { 2 | return {type: 'increase'}; 3 | } 4 | 5 | export function multiAction() { 6 | return {type: 'multi'}; 7 | } 8 | -------------------------------------------------------------------------------- /app/components/about.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {ButtonGroup, Button} from 'react-bootstrap'; 3 | class About extends React.Component { 4 | render() { 5 | return ( 6 |
7 |

关于

8 | 9 | 10 | 11 | 12 |
Hello World!
13 |
14 | ) 15 | } 16 | } 17 | module.exports = About; 18 | -------------------------------------------------------------------------------- /app/components/basic.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {BrowserRouter as Router, Route, Link, Redirect, HashRouter} from 'react-router-dom' 3 | import {createBrowserHistory, createHashHistory} from 'history' 4 | const history = createHashHistory() 5 | //引入组件 6 | import Home from "./home.jsx"; 7 | import Topics from "./topics.jsx"; 8 | import About from "./about.jsx"; 9 | import {ButtonGroup, Button} from 'react-bootstrap'; 10 | 11 | import {increaseAction, multiAction} from '../action.js'; 12 | 13 | import {connect} from 'react-redux'; 14 | 15 | import {Tab, Tabs} from 'react-bootstrap'; 16 | 17 | // React component 18 | class Basic extends React.Component { 19 | constructor(props) { 20 | super(props); 21 | // 设置 initial state 22 | this.state = { 23 | text: props.initialValue || 'Hello Wscats' 24 | }; 25 | // ES6 类中函数必须手动绑定 26 | this.handleSubmit = this.handleSubmit.bind(this); 27 | } 28 | handleSubmit(event) { 29 | var page = event.target.id.charAt(event.target.id.length - 1); 30 | switch (page) { 31 | case "1": 32 | history.push('/'); 33 | break; 34 | case "2": 35 | history.push('/about'); 36 | break; 37 | case "3": 38 | history.push('/topics'); 39 | break; 40 | } 41 | } 42 | render() { 43 | const {value, onIncreaseClick} = this.props 44 | return ( 45 | 46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 |

{value}

54 | 55 | {/**/} 66 |
67 | 68 | 69 | 70 | {/*默认跳转*/} 71 |
72 |
73 | ) 74 | } 75 | } 76 | 77 | // Map Redux state to component props 78 | function mapStateToProps(state) { 79 | return {value: state.count} 80 | } 81 | 82 | // Map Redux actions to component props 83 | function mapDispatchToProps(dispatch) { 84 | return { 85 | onIncreaseClick: () => { 86 | //可以触发多个 87 | dispatch(increaseAction()) 88 | dispatch(multiAction()) 89 | } 90 | } 91 | } 92 | // Connected Component 93 | export default connect(mapStateToProps, mapDispatchToProps)(Basic); 94 | -------------------------------------------------------------------------------- /app/components/home.jsx: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | class ProductBox extends React.Component { 3 | render() { 4 | return( 5 |
Hello World!
6 | ) 7 | } 8 | } 9 | module.exports = ProductBox; -------------------------------------------------------------------------------- /app/components/test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | class Test extends React.Component { 3 | render(){ 4 | return ( 5 |
这是一个测试组件{this.props.skill} 6 | 7 |
8 | ) 9 | } 10 | onTap(){ 11 | console.log("test") 12 | } 13 | } 14 | module.exports = Test; -------------------------------------------------------------------------------- /app/components/topics.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {BrowserRouter as Router, Route, Link} from 'react-router-dom' 3 | 4 | import {connect} from 'react-redux'; 5 | 6 | import {increaseAction, multiAction} from '../action.js'; 7 | import Test from './test.jsx' 8 | const Topic = ({match}) => ( 9 |
10 |

{match.params.topicId}

11 |
12 | ) 13 | class Topics extends React.Component { 14 | render() { 15 | const {value, onIncreaseClick} = this.props; 16 | return ( 17 |
18 |

主题列表

19 |

{value}

20 | 21 | 38 | 39 | 40 | ( 41 |

请选择一个主题。

42 | )}/> 43 |
44 | ) 45 | } 46 | } 47 | 48 | // Map Redux state to component props 49 | function mapStateToProps(state) { 50 | return {value: state.count} 51 | } 52 | 53 | // Map Redux actions to component props 54 | function mapDispatchToProps(dispatch) { 55 | return { 56 | onIncreaseClick: () => { 57 | //可以触发多个 58 | dispatch(increaseAction()) 59 | dispatch(multiAction()) 60 | } 61 | } 62 | } 63 | 64 | // Connected Component 让Topics也连接上store 65 | module.exports = connect(mapStateToProps, mapDispatchToProps)(Topics); 66 | -------------------------------------------------------------------------------- /app/main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import Basic from "./components/basic.jsx"; 4 | 5 | //redux 6 | import {Provider, connect} from 'react-redux'; 7 | import {createStore} from 'redux'; 8 | 9 | //模块化action,方便在组件中调用 10 | import {increaseAction, multiAction} from './action.js'; 11 | //模块化reducer 12 | import counter from './reducer.js'; 13 | 14 | // Store 15 | const store = createStore(counter); 16 | 17 | // Action 18 | // const increaseAction = { 19 | // type: 'increase' 20 | // } 21 | // 22 | // const multiAction = { 23 | // type: 'multi' 24 | // } 25 | 26 | // Reducer 27 | // function counter(state = { 28 | // count: 0 29 | // }, action) { 30 | // const count = state.count 31 | // switch (action.type) { 32 | // case 'increase': 33 | // return { 34 | // count: count + 2 35 | // } 36 | // case 'multi': 37 | // return { 38 | // count: count * 2 39 | // } 40 | // default: 41 | // return state 42 | // } 43 | // } 44 | 45 | // 放在Basic入面connect 46 | // // Map Redux state to component props 47 | // function mapStateToProps(state) { 48 | // return {value: state.count} 49 | // } 50 | // 51 | // // Map Redux actions to component props 52 | // function mapDispatchToProps(dispatch) { 53 | // return { 54 | // onIncreaseClick: () => { 55 | // //可以触发多个 56 | // dispatch(increaseAction()) 57 | // dispatch(multiAction()) 58 | // } 59 | // } 60 | // } 61 | 62 | // Connected Component 63 | //const App = connect(mapStateToProps, mapDispatchToProps)(Basic) 64 | 65 | ReactDOM.render(( 66 | 67 | 68 | 69 | ), document.getElementById('root')) 70 | -------------------------------------------------------------------------------- /app/reducer.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = { 2 | count: 0 3 | }, action) { 4 | const count = state.count 5 | switch (action.type) { 6 | case 'increase': 7 | return { 8 | count: count + 2 9 | } 10 | case 'multi': 11 | return { 12 | count: count * 2 13 | } 14 | default: 15 | return state 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | React Test 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "babel-core": "6.24.1", 4 | "babel-loader": "7.0.0", 5 | "babel-preset-es2015": "6.24.1", 6 | "babel-preset-react": "6.24.1", 7 | "less-loader": "4.0.3", 8 | "react": "15.5.4", 9 | "react-dom": "15.5.4", 10 | "react-router-dom": "4.1.1", 11 | "style-loader": "0.16.1", 12 | "url-loader": "0.5.8", 13 | "webpack": "2.4.1", 14 | "webpack-dev-server": "2.4.2", 15 | "history": "4.6.1", 16 | "react-bootstrap": "0.31.0", 17 | "react-redux": "5.0.5", 18 | "react-router-config": "1.0.0-beta.3", 19 | "redux": "3.6.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # install 2 | ```bash 3 | npm install 4 | ``` 5 | 6 | # run 7 | ```bash 8 | webpack-dev-server 9 | ``` 10 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | //__dirname是node.js中的一个全局变量,它指向当前执行脚本所在的目录 2 | module.exports = { //注意这里是exports不是export 3 | devtool: 'eval-source-map', //生成Source Maps,这里选择eval-source-map 4 | entry: __dirname + "/app/main.js", //唯一入口文件 5 | output: { //输出目录 6 | path: __dirname + "/build", //打包后的js文件存放的地方 7 | filename: 'bundle.js', //打包后的js文件名 8 | }, 9 | module: { 10 | loaders: [{ 11 | test: /\.js[x]?$/, //匹配到js或jsx文件后 使用 babel-loader 来处理 12 | exclude: /node_modules/, //屏蔽不需要处理的文件(文件夹)(可选) 13 | loader: 'babel-loader' 14 | //npm install babel-loader 15 | //npm install babel-core 16 | }, { 17 | test: /\.css$/, 18 | loader: 'style-loader!css-loader' 19 | }, { 20 | test: /\.less$/, 21 | loader: 'style-loader!css-loader!less-loader' 22 | }, { 23 | test: /\.(png|jpg)$/, 24 | loader: 'url-loader?limit=25000' 25 | }] 26 | }, 27 | devServer: { 28 | contentBase: './build', //默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到"build"目录) 29 | historyApiFallback: true, //在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html 30 | inline: true, //设置为true,当源文件改变时会自动刷新页面 31 | port: 12345, //设置默认监听端口,如果省略,默认为"8080" 32 | } 33 | }; --------------------------------------------------------------------------------