├── .gitignore
├── todoMvc
├── todoMvc-1step
│ ├── src
│ │ ├── styles
│ │ │ └── main.styl
│ │ ├── entry.js
│ │ └── components
│ │ │ └── app.js
│ ├── index.html
│ ├── webpack.config.js
│ ├── package.json
│ ├── README.md
│ └── out
│ │ └── bundle.js
├── todoMvc-2step
│ ├── src
│ │ ├── styles
│ │ │ └── main.styl
│ │ ├── entry.js
│ │ ├── components
│ │ │ └── app.js
│ │ └── js
│ │ │ └── localDb.js
│ ├── index.html
│ ├── webpack.config.js
│ ├── package.json
│ └── README.md
├── todoMvc-3step
│ ├── src
│ │ ├── styles
│ │ │ └── main.styl
│ │ ├── components
│ │ │ ├── TodoFooter.js
│ │ │ ├── TodoItem.js
│ │ │ ├── TodoHeader.js
│ │ │ ├── TodoMain.js
│ │ │ └── app.js
│ │ ├── entry.js
│ │ └── js
│ │ │ └── localDb.js
│ ├── index.html
│ ├── webpack.config.js
│ ├── package.json
│ └── README.md
├── todoMvc-4step
│ ├── .babelrc
│ ├── src
│ │ ├── entry.js
│ │ ├── components
│ │ │ ├── TodoMain.js
│ │ │ ├── TodoFooter.js
│ │ │ ├── TodoItem.js
│ │ │ ├── TodoHeader.js
│ │ │ └── app.js
│ │ ├── styles
│ │ │ └── main.styl
│ │ └── js
│ │ │ └── localDb.js
│ ├── index.html
│ ├── webpack.config.js
│ ├── package.json
│ └── README.md
├── todoMvc-5step
│ ├── .babelrc
│ ├── src
│ │ ├── entry.js
│ │ ├── components
│ │ │ ├── TodoFooter.js
│ │ │ ├── TodoMain.js
│ │ │ ├── TodoItem.js
│ │ │ ├── Login.js
│ │ │ ├── TodoHeader.js
│ │ │ └── app.js
│ │ ├── styles
│ │ │ └── main.styl
│ │ └── js
│ │ │ └── localDb.js
│ ├── index.html
│ ├── webpack.config.js
│ ├── package.json
│ └── README.md
└── README.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea/
3 | .DS_Store/
--------------------------------------------------------------------------------
/todoMvc/todoMvc-1step/src/styles/main.styl:
--------------------------------------------------------------------------------
1 | .todo-title
2 | color red
--------------------------------------------------------------------------------
/todoMvc/todoMvc-2step/src/styles/main.styl:
--------------------------------------------------------------------------------
1 | .todo-title
2 | color green
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-demo
2 | ####react 学习仓库
3 |
4 | 欢迎 star,fork,提交issues
5 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/src/styles/main.styl:
--------------------------------------------------------------------------------
1 | .todo-title
2 | color red
3 | font-family "Weibei TC"
--------------------------------------------------------------------------------
/todoMvc/todoMvc-1step/src/entry.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | require('./components/app')
3 | require('./styles/main.styl')
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/src/components/TodoFooter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [["import", {"libraryName": "antd", "style": "css"}]]
3 | }
4 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [["import", {"libraryName": "antd", "style": "css"}]]
3 | }
4 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-1step/src/components/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 16/02/2017.
3 | */
4 | alert('success')
--------------------------------------------------------------------------------
/todoMvc/todoMvc-2step/src/entry.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | // require('./components/app')
3 | // require('./styles/main.styl')
4 |
5 | import './components/app' //es6写法
6 | import './styles/main.styl' //es6写法
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/src/entry.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | // require('./components/app')
3 | // require('./styles/main.styl')
4 |
5 | import './components/app' //es6写法
6 | import './styles/main.styl' //es6写法
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/src/entry.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | // require('./components/app')
3 | // require('./styles/main.styl')
4 |
5 | import './components/app' //es6写法
6 | import './styles/main.styl' //es6写法
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/src/entry.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | // require('./components/app')
3 | // require('./styles/main.styl')
4 |
5 | import './components/app' //es6写法
6 | import './styles/main.styl' //es6写法
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | react
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | react
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-1step/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | react
6 |
7 |
8 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-2step/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | react
6 |
7 |
8 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | react
6 |
7 |
8 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/src/components/TodoItem.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 |
6 | class TodoItem extends React.Component {
7 | render() {
8 | let className = this.props.isDone?'task-done':''
9 | return (
10 |
11 |
12 |
13 | {this.props.text}
14 |
15 |
16 | )
17 | }
18 | }
19 |
20 | export default TodoItem
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: [
3 | "./src/entry.js" //入口文件
4 | ],
5 | output: {
6 | path: './out/',
7 | filename: "bundle.js" //输出文件
8 | },
9 | module: {
10 | loaders: [
11 | { test: /\.js[x]?$/, loader: "babel-loader?presets[]=es2015&presets[]=react", include: /src/},//支持es6
12 | { test: /\.css$/, loader: "style-loader!css-loader"},
13 | { test: /\.styl$/, loader: "style-loader!css-loader!stylus-loader"},//支持stylus
14 | { test: /\.(png|jpg)$/, loader: 'url?limit=8192'}
15 | ]
16 | }
17 | };
--------------------------------------------------------------------------------
/todoMvc/todoMvc-1step/webpack.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 16/02/2017.
3 | */
4 | module.exports = {
5 | entry: [
6 | "./src/entry.js"
7 | ],
8 | output: {
9 | path: './out/',
10 | filename: "bundle.js"
11 | },
12 | module: {
13 | loaders: [
14 | { test: /\.js[x]?$/, loader: "babel-loader?presets[]=es2015&presets[]=react", include: /src/},
15 | { test: /\.css$/, loader: "style!css"},
16 | { test: /\.styl$/, loader: "style-loader!css-loader!stylus-loader"},
17 | { test: /\.(png|jpg)$/, loader: 'url?limit=8192'}
18 | ]
19 | }
20 | };
--------------------------------------------------------------------------------
/todoMvc/todoMvc-2step/webpack.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 16/02/2017.
3 | */
4 | module.exports = {
5 | entry: [
6 | "./src/entry.js" //入口文件
7 | ],
8 | output: {
9 | path: './out/',
10 | filename: "bundle.js" //输出文件
11 | },
12 | module: {
13 | loaders: [
14 | { test: /\.js[x]?$/, loader: "babel-loader?presets[]=es2015&presets[]=react", include: /src/},//支持es6
15 | { test: /\.css$/, loader: "style!css"},
16 | { test: /\.styl$/, loader: "style-loader!css-loader!stylus-loader"},//支持stylus
17 | { test: /\.(png|jpg)$/, loader: 'url?limit=8192'}
18 | ]
19 | }
20 | };
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/webpack.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 16/02/2017.
3 | */
4 | module.exports = {
5 | entry: [
6 | "./src/entry.js" //入口文件
7 | ],
8 | output: {
9 | path: './out/',
10 | filename: "bundle.js" //输出文件
11 | },
12 | module: {
13 | loaders: [
14 | { test: /\.js[x]?$/, loader: "babel-loader?presets[]=es2015&presets[]=react", include: /src/},//支持es6
15 | { test: /\.css$/, loader: "style!css"},
16 | { test: /\.styl$/, loader: "style-loader!css-loader!stylus-loader"},//支持stylus
17 | { test: /\.(png|jpg)$/, loader: 'url?limit=8192'}
18 | ]
19 | }
20 | };
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/webpack.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 16/02/2017.
3 | */
4 | module.exports = {
5 | entry: [
6 | "./src/entry.js" //入口文件
7 | ],
8 | output: {
9 | path: './out/',
10 | filename: "bundle.js" //输出文件
11 | },
12 | module: {
13 | loaders: [
14 | { test: /\.js[x]?$/, loader: "babel-loader?presets[]=es2015&presets[]=react", include: /src/},//支持es6
15 | { test: /\.css$/, loader: "style-loader!css-loader"},
16 | { test: /\.styl$/, loader: "style-loader!css-loader!stylus-loader"},//支持stylus
17 | { test: /\.(png|jpg)$/, loader: 'url?limit=8192'}
18 | ]
19 | }
20 | };
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/src/components/TodoHeader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 |
6 | class TodoHeader extends React.Component {
7 | // 绑定键盘回车事件,添加新任务
8 | handlerKeyUp(e) {
9 | if(e.keyCode == 13) {
10 | let value = e.target.value;
11 | if(!value) return false;
12 | let newTodoItem = {
13 | text: value,
14 | isDone: false
15 | };
16 | e.target.value = '';
17 | this.props.addTodo(newTodoItem)
18 | }
19 | }
20 | render(){
21 | return (
22 |
23 |
24 |
25 | )
26 | }
27 | }
28 | export default TodoHeader
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/src/components/TodoMain.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 | import TodoItem from './TodoItem'
6 |
7 | class TodoMain extends React.Component {
8 | render(){
9 | if(this.props.todos.length == 0) {
10 | return (
11 | 恭喜您,目前没有待办任务
12 | )
13 | } else {
14 | return (
15 |
16 | {
17 | this.props.todos.map((todo,index) => {
18 | //{...this.props} 用来传递TodoMain的todos属性和delete、change方法。
19 | return
20 | })
21 | }
22 |
23 | )
24 | }
25 | }
26 | }
27 | export default TodoMain
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/src/components/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 16/02/2017.
3 | */
4 | import React from 'react'
5 | import ReactDOM from 'react-dom'
6 | import TodoHeader from './TodoHeader'
7 | import TodoMain from './TodoMain'
8 |
9 | class App extends React.Component { //定义组件,继承父类
10 | constructor() {
11 | super()
12 | this.state = {
13 | todos: []
14 | }
15 | }
16 | addTodo(item) {
17 | this.state.todos.push(item)
18 | this.setState({todos: this.state.todos}); //设置状态
19 | }
20 | render(){
21 | return (
22 |
23 |
24 |
25 |
26 | )
27 | }
28 | }
29 |
30 |
31 | ReactDOM.render( ,document.getElementById('app'))
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/src/components/TodoMain.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 | import TodoItem from './TodoItem'
6 |
7 | class TodoMain extends React.Component {
8 | render(){
9 | if(this.props.todos.length == 0) {
10 | return (
11 | 恭喜您,目前没有待办任务
12 | )
13 | } else {
14 | return (
15 |
16 | {
17 | this.props.todos.map((todo,index) => {
18 | //{...this.props} 用来传递TodoMain的todos属性和delete、change方法。
19 | return
20 | })
21 | }
22 |
23 | )
24 | }
25 | }
26 | }
27 | export default TodoMain
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/src/components/TodoFooter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 | import { Button,Checkbox } from 'antd'
6 |
7 | class TodoFooter extends React.Component{
8 | deleteAll(){
9 | this.props.clearDone()
10 | }
11 | changeAll(e){
12 | this.props.changeTodoState(null,e.target.checked,true)
13 | }
14 | render(){
15 | let minus = this.props.todoCount - this.props.todoDoneCount
16 | return (
17 |
18 |
19 | 全选
20 |
21 | 还剩{minus}未完成
22 | 清除全部已完成
23 |
24 | )
25 | }
26 | }
27 |
28 | export default TodoFooter
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/src/styles/main.styl:
--------------------------------------------------------------------------------
1 | #app
2 | width 60%
3 | padding 20px
4 | margin 0 auto
5 | .todo-empty
6 | text-align center
7 | padding 10px 0
8 | font-size 16px
9 | .todo-title
10 | color red
11 | font-family "Weibei TC"
12 | text-align center
13 | .todo-main
14 | li
15 | padding 10px 0
16 | height 50px
17 | .time
18 | display inline-block
19 | vertical-align top
20 | width 31%
21 | min-width 160px
22 | font-size 16px
23 | .task
24 | display inline-block
25 | vertical-align top
26 | width 56%
27 | font-size 16px
28 | &.task-done
29 | text-decoration line-through
30 | .ant-btn
31 | vertical-align top
32 | display none
33 | .todo-footer
34 | display flex
35 | justify-content space-between
36 | font-size 14px
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/src/components/TodoFooter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 | import { Button,Checkbox } from 'antd'
6 |
7 | class TodoFooter extends React.Component{
8 | deleteAll(){
9 | this.props.clearDone()
10 | }
11 | changeAll(e){
12 | this.props.changeTodoState(null,e.target.checked,true)
13 | }
14 | render(){
15 | let minus = this.props.todoCount - this.props.todoDoneCount
16 | return (
17 |
18 |
19 | 全选
20 |
21 | 还剩{minus}未完成
22 | 清除全部已完成
23 |
24 | )
25 | }
26 | }
27 |
28 | export default TodoFooter
--------------------------------------------------------------------------------
/todoMvc/todoMvc-2step/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tomvc",
3 | "version": "1.0.0",
4 | "description": "react",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "react-demo"
11 | ],
12 | "author": "zxw",
13 | "license": "ISC",
14 | "dependencies": {
15 | "normalize.css": "^5.0.0",
16 | "react": "^15.4.2",
17 | "react-dom": "^15.4.2"
18 | },
19 | "devDependencies": {
20 | "babel-core": "^6.22.1",
21 | "babel-loader": "^6.2.10",
22 | "babel-preset-es2015": "^6.18.0",
23 | "babel-preset-react": "^6.16.0",
24 | "css-loader": "^0.14.5",
25 | "file-loader": "^0.8.4",
26 | "jsx-loader": "^0.13.2",
27 | "node-libs-browser": "^0.5.2",
28 | "style-loader": "^0.12.3",
29 | "stylus-loader": "^1.0.2",
30 | "url-loader": "^0.5.6",
31 | "webpack": "^2.2.1"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tomvc",
3 | "version": "1.0.0",
4 | "description": "react",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "react-demo"
11 | ],
12 | "author": "zxw",
13 | "license": "ISC",
14 | "dependencies": {
15 | "normalize.css": "^5.0.0",
16 | "react": "^15.4.2",
17 | "react-dom": "^15.4.2"
18 | },
19 | "devDependencies": {
20 | "babel-core": "^6.22.1",
21 | "babel-loader": "^6.2.10",
22 | "babel-preset-es2015": "^6.18.0",
23 | "babel-preset-react": "^6.16.0",
24 | "css-loader": "^0.14.5",
25 | "file-loader": "^0.8.4",
26 | "jsx-loader": "^0.13.2",
27 | "node-libs-browser": "^0.5.2",
28 | "style-loader": "^0.12.3",
29 | "stylus-loader": "^1.0.2",
30 | "url-loader": "^0.5.6",
31 | "webpack": "^2.2.1"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/src/components/TodoMain.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 | import TodoItem from './TodoItem'
6 |
7 | class TodoMain extends React.Component {
8 | componentDidUpdate() {
9 | this.props.saveOrUpdateTodos()
10 | }
11 | render(){
12 | if(this.props.todos.length == 0) {
13 | return (
14 | 恭喜您,目前没有待办任务!
15 | )
16 | } else {
17 | return (
18 |
19 | {
20 | this.props.todos.map((todo,index) => {
21 | //{...this.props} 用来传递TodoMain的todos属性和delete、change方法。
22 | return
23 | })
24 | }
25 |
26 | )
27 | }
28 | }
29 | }
30 | export default TodoMain
--------------------------------------------------------------------------------
/todoMvc/todoMvc-1step/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tomvc",
3 | "version": "1.0.0",
4 | "description": "react",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "react-demo"
11 | ],
12 | "author": "zxw",
13 | "license": "ISC",
14 | "dependencies": {
15 | "normalize.css": "^5.0.0",
16 | "react": "^15.4.2",
17 | "react-dom": "^15.4.2"
18 | },
19 | "devDependencies": {
20 | "babel-core": "^6.22.1",
21 | "babel-loader": "^6.2.10",
22 | "babel-preset-es2015": "^6.18.0",
23 | "babel-preset-react": "^6.16.0",
24 | "css-loader": "^0.14.5",
25 | "file-loader": "^0.8.4",
26 | "jsx-loader": "^0.13.2",
27 | "node-libs-browser": "^0.5.2",
28 | "style-loader": "^0.12.3",
29 | "stylus": "^0.54.5",
30 | "stylus-loader": "^1.0.2",
31 | "url-loader": "^0.5.6",
32 | "webpack": "^2.2.1"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tomvc",
3 | "version": "1.0.0",
4 | "description": "react",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "react-demo"
11 | ],
12 | "author": "zxw",
13 | "license": "ISC",
14 | "dependencies": {
15 | "antd": "^2.7.1",
16 | "normalize.css": "^5.0.0",
17 | "react": "^15.4.2",
18 | "react-dom": "^15.4.2"
19 | },
20 | "devDependencies": {
21 | "babel-core": "^6.22.1",
22 | "babel-loader": "^6.2.10",
23 | "babel-plugin-import": "^1.1.1",
24 | "babel-preset-es2015": "^6.18.0",
25 | "babel-preset-react": "^6.16.0",
26 | "css-loader": "^0.14.5",
27 | "file-loader": "^0.8.4",
28 | "jsx-loader": "^0.13.2",
29 | "node-libs-browser": "^0.5.2",
30 | "style-loader": "^0.12.3",
31 | "stylus-loader": "^1.0.2",
32 | "url-loader": "^0.5.6",
33 | "webpack": "^2.2.1"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tomvc",
3 | "version": "1.0.0",
4 | "description": "react",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "webpack-dev-server",
9 | "build": "webpack"
10 | },
11 | "keywords": [
12 | "react-demo"
13 | ],
14 | "author": "zxw",
15 | "license": "ISC",
16 | "dependencies": {
17 | "antd": "^2.7.1",
18 | "leancloud-storage": "^2.1.2",
19 | "normalize.css": "^5.0.0",
20 | "react": "^15.4.2",
21 | "react-dom": "^15.4.2"
22 | },
23 | "devDependencies": {
24 | "babel-core": "^6.22.1",
25 | "babel-loader": "^6.2.10",
26 | "babel-plugin-import": "^1.1.1",
27 | "babel-preset-es2015": "^6.18.0",
28 | "babel-preset-react": "^6.16.0",
29 | "css-loader": "^0.14.5",
30 | "file-loader": "^0.8.4",
31 | "html-webpack-plugin": "^2.28.0",
32 | "jsx-loader": "^0.13.2",
33 | "node-libs-browser": "^0.5.2",
34 | "style-loader": "^0.12.3",
35 | "stylus-loader": "^1.0.2",
36 | "url-loader": "^0.5.6",
37 | "webpack": "^2.2.1",
38 | "webpack-dev-server": "^2.4.1",
39 | "webpack-merge": "^3.0.0"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/src/components/TodoItem.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 | import ReactDOM from 'react-dom'
6 | import { Button,Checkbox } from 'antd'
7 |
8 | class TodoItem extends React.Component {
9 | handlerChange() {
10 | let isDone = !this.props.isDone;
11 | this.props.changeTodoState(this.props.index, isDone);
12 | }
13 | handlerDelete() {
14 | this.props.deleteTodo(this.props.index)
15 | }
16 | handlerMouseIn () {
17 | ReactDOM.findDOMNode(this.refs.delButton).style.display = 'inline-block'
18 | }
19 | handlerMouseOut () {
20 | ReactDOM.findDOMNode(this.refs.delButton).style.display = 'none'
21 | }
22 | render() {
23 | let className = this.props.isDone?'task-done':''
24 | return (
25 |
26 |
27 | {this.props.time}
28 | {this.props.text}
29 | 删除
30 |
31 | )
32 | }
33 | }
34 |
35 | export default TodoItem
--------------------------------------------------------------------------------
/todoMvc/README.md:
--------------------------------------------------------------------------------
1 | #### 此项目记录了本人从零开始学习用业余时间做经典的 React-todoMVC
2 |
3 | 每个step做一个关键知识点,循序渐进,希望可以帮助像我一样刚开始找不到头绪的同学,近期我会把详细教程也写出来
4 |
5 | ####文件目录
6 |
7 | 1. [todoMvc-1step](https://github.com/Zegendary/react-demo/tree/master/todoMvc/todoMvc-1step) [演示1](https://zegendary.github.io/react-demo/todoMvc/todoMvc-1step/) webpack+react项目构建
8 |
9 | 2. [todoMvc-2step](https://github.com/Zegendary/react-demo/tree/master/todoMvc/todoMvc-2step) [演示2](https://zegendary.github.io/react-demo/todoMvc/todoMvc-2step/) 实现双向绑定功能
10 |
11 | 3. [todoMvc-3step](https://github.com/Zegendary/react-demo/tree/master/todoMvc/todoMvc-3step) [演示3](https://zegendary.github.io/react-demo/todoMvc/todoMvc-3step/) 将项目组件化
12 |
13 | 4. [todoMvc-4step](https://github.com/Zegendary/react-demo/tree/master/todoMvc/todoMvc-4step) [演示4](https://zegendary.github.io/react-demo/todoMvc/todoMvc-4step/) 完成todoMvc所有功能,包括全选,清除全部已完成,并引入[Ant-Design](https://ant.design/index-cn)UI
14 |
15 | 5. [todoMvc-5step](https://github.com/Zegendary/react-demo/tree/master/todoMvc/todoMvc-5step) [演示5](https://zegendary.github.io/react-demo/todoMvc/todoMvc-5step/) 利用LeanCloud第三方储存,将账户,密码,已经todo内容存储到第三方服务器中
16 |
17 | 如何打开本项目下的demo?
18 |
19 | 1. `git clone git@github.com:Zegendary/react-demo.git`
20 |
21 | 2. `cd react-demo/todoMvc/你感兴趣的步骤`
22 |
23 | 3. `npm install`
24 |
25 | 4. `webpack -w`
26 |
27 | 5. `open index.html`
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/src/components/TodoItem.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 | import ReactDOM from 'react-dom'
6 | import { Button,Checkbox } from 'antd'
7 |
8 | class TodoItem extends React.Component {
9 | handlerChange() {
10 | let isDone = !this.props.isDone;
11 | this.props.changeTodoState(this.props.index, isDone);
12 | }
13 | handlerDelete() {
14 | this.props.deleteTodo(this.props.index)
15 | }
16 | handlerMouseIn () {
17 | ReactDOM.findDOMNode(this.refs.delButton).style.display = 'inline-block'
18 | }
19 | handlerMouseOut () {
20 | ReactDOM.findDOMNode(this.refs.delButton).style.display = 'none'
21 | }
22 | render() {
23 | let className = this.props.isDone?'task-done':''
24 | return (
25 |
26 |
27 |
28 | {this.props.time}
29 | {this.props.text}
30 |
31 | 删除
32 |
33 | )
34 | }
35 | }
36 |
37 | export default TodoItem
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/src/styles/main.styl:
--------------------------------------------------------------------------------
1 | #app
2 | width 60%
3 | padding 20px
4 | margin 0 auto
5 | .todo-empty
6 | text-align center
7 | padding 10px 0
8 | font-size 16px
9 | .todo-title
10 | color red
11 | font-family "Weibei TC"
12 | text-align center
13 | .user-info
14 | display flex
15 | justify-content space-between
16 | font-size 14px
17 | margin 10px 0
18 | .todo-main
19 | li
20 | padding 10px 0
21 | height 50px
22 | .time-task
23 | display inline-block
24 | vertical-align top
25 | width calc(100% - 75px)
26 | font-size 0
27 | .time
28 | display inline-block
29 | vertical-align top
30 | width 40%
31 | font-size 16px
32 | .task
33 | display inline-block
34 | vertical-align top
35 | width 60%
36 | font-size 16px
37 | &.task-done
38 | text-decoration line-through
39 | .ant-btn
40 | vertical-align top
41 | display none
42 | width 50px
43 | .todo-footer
44 | display flex
45 | justify-content space-between
46 | font-size 14px
47 | .form-wrapper
48 | width 250px
49 | margin 0 auto
50 | .radio-wrapper
51 | margin 10px 0
52 | width 100%
53 | text-align center
54 | .login-form-button
55 | width 100%
--------------------------------------------------------------------------------
/todoMvc/todoMvc-2step/src/components/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 16/02/2017.
3 | */
4 | import React from 'react'
5 | import ReactDOM from 'react-dom'
6 |
7 | class App extends React.Component { //定义组件,继承父类
8 | constructor() {//constructor 是和 class 一起用来创建和初始化对象的特殊方法。
9 | super()//在装载组件(mounting)之前调用会React组件的构造函数。当实现React.Component子类的构造函数时,应该在任何其他语句之前调用super(props)
10 | this.state = {//设置初始状态
11 | todos: []
12 | }
13 | }
14 | // 绑定键盘回车事件,添加新任务
15 | handlerKeyUp(e) {
16 | if(e.keyCode == 13) {
17 | let value = e.target.value;
18 | if(!value) return false;
19 | let newTodoItem = {
20 | text: value,
21 | isDone: false
22 | };
23 | e.target.value = '';
24 | this.state.todos.push(newTodoItem)
25 | this.setState({todos: this.state.todos}); //修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。
26 | }
27 | }
28 | render(){
29 | return (
30 |
31 |
32 |
33 | {this.state.todos.map((todo,index) => {{
34 | return (
35 | {todo.text} //Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity
36 | )
37 | }})}
38 |
39 |
40 | )
41 | }
42 | }
43 |
44 |
45 | ReactDOM.render( ,document.getElementById('app'))
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/src/components/Login.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 20/02/2017.
3 | */
4 | import React from 'react'
5 | import { Form, Icon, Input, Button } from 'antd';
6 |
7 | const FormItem = Form.Item;
8 |
9 | const Login = Form.create()(React.createClass({
10 | handleSubmit(e) {
11 | e.preventDefault();
12 | this.props.form.validateFields((err, values) => {
13 | if (!err) {
14 | this.props.loginOrSignUp(values)
15 | }
16 | });
17 | },
18 | render() {
19 | const { getFieldDecorator } = this.props.form;
20 | let text = this.props.value == 1 ?'注册':'登陆'
21 | return (
22 |
43 | );
44 | },
45 | }));
46 | export default Login
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/src/components/TodoHeader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 | import ReactDOM from 'react-dom'
6 | import { Input } from 'antd'
7 |
8 | class TodoHeader extends React.Component {
9 | // 绑定键盘回车事件,添加新任务
10 | handlerKeyUp(e) {
11 | if(e.keyCode == 13) {
12 | let value = e.target.value;
13 | if(!value) return false;
14 | let date = new Date().Format("yyyy-MM-dd hh:mm")
15 | let newTodoItem = {
16 | text: value,
17 | isDone: false,
18 | time: date
19 | };
20 | e.target.value = '';
21 | this.props.addTodo(newTodoItem)
22 | }
23 | }
24 | componentWillMount() {
25 | //日期格式化
26 | Date.prototype.Format = function (fmt) {
27 | var o = {
28 | "M+": this.getMonth() + 1, //月份
29 | "d+": this.getDate(), //日
30 | "h+": this.getHours(), //小时
31 | "m+": this.getMinutes(), //分
32 | "s+": this.getSeconds(), //秒
33 | "q+": Math.floor((this.getMonth() + 3) / 3), //季度
34 | "S": this.getMilliseconds() //毫秒
35 | };
36 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
37 | for (var k in o)
38 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
39 | return fmt;
40 | }
41 | }
42 | render(){
43 | return (
44 |
45 |
React-Todos
46 |
47 |
48 | )
49 | }
50 | }
51 | export default TodoHeader
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/README.md:
--------------------------------------------------------------------------------
1 | [todoMvc-4step源码](https://github.com/Zegendary/react-demo/tree/master/todoMvc/todoMvc-4step)
2 |
3 | [todoMvc-4step演示](https://zegendary.github.io/react-demo/todoMvc/todoMvc-4step/)
4 |
5 | 这一章主要以【删除】键为例讲一下如何使用以 [React](http://facebook.github.io/react/) 封装了一套 [Ant Design](https://ant.design/index-cn) 的组件库:
6 |
7 | 
8 |
9 | ### 1.安装
10 |
11 | 推荐使用 npm 的方式进行开发,不仅可在开发环境轻松调试,也可放心地在生产环境打包部署使用,享受整个生态圈和工具链带来的诸多好处。
12 | 可以通过 npm 直接安装到项目中,使用 `import` 或 `require` 进行引用。
13 |
14 | $ npm install antd --save
15 |
16 | ### 2.加载
17 |
18 | 可以通过以下的写法来按需加载组件。
19 |
20 | import Button from 'antd/lib/button';
21 | import 'antd/lib/button/style'; // 或者 antd/lib/button/style/css 加载 css 文件
22 |
23 | 但我推荐使用更简便的写法:
24 | 首先需要安装[babel-plugin-import](https://github.com/ant-design/babel-plugin-import) 依赖
25 |
26 | $ npm install babel-plugin-import --save-dev
27 |
28 | 然后在我们的根目录下新建`.babelrc`:
29 |
30 | {
31 | "plugins": [["import", {"libraryName": "antd", "style": "css"}]] //import js and css modularly
32 | }
33 |
34 | 这时我们需要什么UI组件,即可如下这么写以达到按需加载`js`和`css`:
35 |
36 | import { Button } from 'antd';
37 |
38 | ### 3.使用
39 |
40 | 由于`Antd`组件已经油`React`封装好了,用法和原生html标签没差:
41 |
42 | 删除
43 |
44 | 剩余的样式我们就可以对着[antd components](https://ant.design/components/button-cn/)的demo来开发。
45 |
46 | [React+webpack从0到1开发一个todoMvc(一)](http://www.jianshu.com/p/aa02a10c5b69)
47 | [React+webpack从0到1开发一个todoMvc(二)](http://www.jianshu.com/p/ed01cf27b23d)
48 | [React+webpack从0到1开发一个todoMvc(三)](http://www.jianshu.com/p/80e54fc179e4)
49 | [React+webpack从0到1开发一个todoMvc(五)](http://www.jianshu.com/p/86b83192917d)
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/src/components/TodoHeader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 17/02/2017.
3 | */
4 | import React from 'react'
5 | import ReactDOM from 'react-dom'
6 | import { Input,Button } from 'antd'
7 |
8 | class TodoHeader extends React.Component {
9 | // 绑定键盘回车事件,添加新任务
10 | handlerKeyUp(e) {
11 | if(e.keyCode == 13) {
12 | let value = e.target.value;
13 | if(!value) return false;
14 | let date = new Date().Format("yyyy-MM-dd hh:mm")
15 | let newTodoItem = {
16 | text: value,
17 | isDone: false,
18 | time: date
19 | };
20 | e.target.value = '';
21 | this.props.addTodo(newTodoItem)
22 | }
23 | }
24 | loginOut(){
25 | this.props.logout()
26 | }
27 | componentWillMount() {
28 | //日期格式化
29 | Date.prototype.Format = function (fmt) {
30 | var o = {
31 | "M+": this.getMonth() + 1, //月份
32 | "d+": this.getDate(), //日
33 | "h+": this.getHours(), //小时
34 | "m+": this.getMinutes(), //分
35 | "s+": this.getSeconds(), //秒
36 | "q+": Math.floor((this.getMonth() + 3) / 3), //季度
37 | "S": this.getMilliseconds() //毫秒
38 | };
39 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
40 | for (var k in o)
41 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
42 | return fmt;
43 | }
44 | }
45 | render(){
46 | return (
47 |
48 |
React-Todos
49 |
50 | {"欢迎你,"+ this.props.currentUser.username}
51 | 登出
52 |
53 |
54 |
55 | )
56 | }
57 | }
58 | export default TodoHeader
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/src/components/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 16/02/2017.
3 | */
4 | import React from 'react'
5 | import ReactDOM from 'react-dom'
6 | import TodoHeader from './TodoHeader'
7 | import TodoMain from './TodoMain'
8 | import TodoFooter from './TodoFooter'
9 |
10 | class App extends React.Component { //定义组件,继承父类
11 | constructor() {
12 | super()
13 | this.state = {
14 | todos: [],
15 | isAllChecked: false
16 | }
17 | }
18 | addTodo(item) {
19 | this.state.todos.push(item)
20 | this.setState({todos: this.state.todos}); //设置状态
21 | }
22 | // 改变任务状态,传递给TodoItem和Footer组件的方法
23 | changeTodoState(index, isDone, isChangeAll=false){ //初始化isChangeAll为false
24 | if(isChangeAll){ //全部操作
25 | this.setState({
26 | todos: this.state.todos.map((todo) => {
27 | todo.isDone = isDone;
28 | return todo;
29 | }),
30 | isAllChecked: isDone
31 | });
32 | }else{ //操作其中一个todo
33 | this.state.todos[index].isDone = isDone;
34 | this.allChecked();
35 | }
36 | }
37 | // 判断是否所有任务的状态都完成,同步底部的全选框
38 | allChecked() {
39 | let isAllChecked = false;
40 | if (this.state.todos.every(todo => todo.isDone)) {
41 | isAllChecked = true;
42 | }
43 | this.setState({ //改变状态,组件重绘
44 | todos: this.state.todos,
45 | isAllChecked: isAllChecked
46 | });
47 | }
48 | clearDone(){
49 | let todos = this.state.todos.filter(todo => !todo.isDone)
50 | this.setState({
51 | todos : todos
52 | })
53 | }
54 | deleteTodo(index) {
55 | this.state.todos.splice(index,1)
56 | this.setState({todos: this.state.todos})
57 | }
58 | render(){
59 | let info = {
60 | isAllChecked: this.state.isAllChecked,
61 | todoCount: this.state.todos.length || 0,
62 | todoDoneCount: (this.state.todos && this.state.todos.filter((todo) => todo.isDone)).length || 0
63 | }
64 | return (
65 |
66 |
67 |
68 |
69 |
70 | )
71 | }
72 | }
73 |
74 |
75 | ReactDOM.render( ,document.getElementById('app'))
--------------------------------------------------------------------------------
/todoMvc/todoMvc-2step/src/js/localDb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by YikaJ on 15/6/10.
3 | */
4 | 'use strict';
5 |
6 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
7 |
8 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
9 |
10 | var LocalDb = (function () {
11 | function LocalDb() {
12 | var localDb = arguments[0] === undefined ? 'localDb' : arguments[0];
13 |
14 | _classCallCheck(this, LocalDb);
15 |
16 | if (!window.localStorage) {
17 | throw new Error('Not supports localStorage');
18 | }
19 | this.localDb = localDb;
20 |
21 | if (localStorage[localDb]) {
22 | this.db = JSON.parse(localStorage[localDb]);
23 | } else {
24 | this.db = {};
25 | }
26 | }
27 |
28 | _createClass(LocalDb, [{
29 | key: 'getDb',
30 | value: function getDb() {
31 | return this.db;
32 | }
33 | }, {
34 | key: 'set',
35 | value: function set(key, value) {
36 | if (key) {
37 | this.db[key] = value;
38 |
39 | return this._saveToLocalStorage();
40 | }
41 |
42 | throw new Error('set参数key不能为空');
43 | }
44 | }, {
45 | key: 'get',
46 | value: function get(key) {
47 | if (key) {
48 | var value = this.db[key];
49 | if (typeof value === 'undefined') {
50 | console.warn(key + '的值不存在');
51 | }
52 | return value;
53 | }
54 |
55 | throw new Error('get参数key不能为空');
56 | }
57 | }, {
58 | key: 'clean',
59 | value: function clean() {
60 | this.db = {};
61 | this._saveToLocalStorage();
62 | }
63 | }, {
64 | key: '_saveToLocalStorage',
65 | value: function _saveToLocalStorage() {
66 | localStorage[this.localDb] = JSON.stringify(this.getDb());
67 | }
68 | }]);
69 |
70 | return LocalDb;
71 | })();
72 |
73 | module.exports = LocalDb;
74 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/src/js/localDb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by YikaJ on 15/6/10.
3 | */
4 | 'use strict';
5 |
6 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
7 |
8 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
9 |
10 | var LocalDb = (function () {
11 | function LocalDb() {
12 | var localDb = arguments[0] === undefined ? 'localDb' : arguments[0];
13 |
14 | _classCallCheck(this, LocalDb);
15 |
16 | if (!window.localStorage) {
17 | throw new Error('Not supports localStorage');
18 | }
19 | this.localDb = localDb;
20 |
21 | if (localStorage[localDb]) {
22 | this.db = JSON.parse(localStorage[localDb]);
23 | } else {
24 | this.db = {};
25 | }
26 | }
27 |
28 | _createClass(LocalDb, [{
29 | key: 'getDb',
30 | value: function getDb() {
31 | return this.db;
32 | }
33 | }, {
34 | key: 'set',
35 | value: function set(key, value) {
36 | if (key) {
37 | this.db[key] = value;
38 |
39 | return this._saveToLocalStorage();
40 | }
41 |
42 | throw new Error('set参数key不能为空');
43 | }
44 | }, {
45 | key: 'get',
46 | value: function get(key) {
47 | if (key) {
48 | var value = this.db[key];
49 | if (typeof value === 'undefined') {
50 | console.warn(key + '的值不存在');
51 | }
52 | return value;
53 | }
54 |
55 | throw new Error('get参数key不能为空');
56 | }
57 | }, {
58 | key: 'clean',
59 | value: function clean() {
60 | this.db = {};
61 | this._saveToLocalStorage();
62 | }
63 | }, {
64 | key: '_saveToLocalStorage',
65 | value: function _saveToLocalStorage() {
66 | localStorage[this.localDb] = JSON.stringify(this.getDb());
67 | }
68 | }]);
69 |
70 | return LocalDb;
71 | })();
72 |
73 | module.exports = LocalDb;
74 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-4step/src/js/localDb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by YikaJ on 15/6/10.
3 | */
4 | 'use strict';
5 |
6 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
7 |
8 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
9 |
10 | var LocalDb = (function () {
11 | function LocalDb() {
12 | var localDb = arguments[0] === undefined ? 'localDb' : arguments[0];
13 |
14 | _classCallCheck(this, LocalDb);
15 |
16 | if (!window.localStorage) {
17 | throw new Error('Not supports localStorage');
18 | }
19 | this.localDb = localDb;
20 |
21 | if (localStorage[localDb]) {
22 | this.db = JSON.parse(localStorage[localDb]);
23 | } else {
24 | this.db = {};
25 | }
26 | }
27 |
28 | _createClass(LocalDb, [{
29 | key: 'getDb',
30 | value: function getDb() {
31 | return this.db;
32 | }
33 | }, {
34 | key: 'set',
35 | value: function set(key, value) {
36 | if (key) {
37 | this.db[key] = value;
38 |
39 | return this._saveToLocalStorage();
40 | }
41 |
42 | throw new Error('set参数key不能为空');
43 | }
44 | }, {
45 | key: 'get',
46 | value: function get(key) {
47 | if (key) {
48 | var value = this.db[key];
49 | if (typeof value === 'undefined') {
50 | console.warn(key + '的值不存在');
51 | }
52 | return value;
53 | }
54 |
55 | throw new Error('get参数key不能为空');
56 | }
57 | }, {
58 | key: 'clean',
59 | value: function clean() {
60 | this.db = {};
61 | this._saveToLocalStorage();
62 | }
63 | }, {
64 | key: '_saveToLocalStorage',
65 | value: function _saveToLocalStorage() {
66 | localStorage[this.localDb] = JSON.stringify(this.getDb());
67 | }
68 | }]);
69 |
70 | return LocalDb;
71 | })();
72 |
73 | module.exports = LocalDb;
74 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/src/js/localDb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by YikaJ on 15/6/10.
3 | */
4 | 'use strict';
5 |
6 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
7 |
8 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
9 |
10 | var LocalDb = (function () {
11 | function LocalDb() {
12 | var localDb = arguments[0] === undefined ? 'localDb' : arguments[0];
13 |
14 | _classCallCheck(this, LocalDb);
15 |
16 | if (!window.localStorage) {
17 | throw new Error('Not supports localStorage');
18 | }
19 | this.localDb = localDb;
20 |
21 | if (localStorage[localDb]) {
22 | this.db = JSON.parse(localStorage[localDb]);
23 | } else {
24 | this.db = {};
25 | }
26 | }
27 |
28 | _createClass(LocalDb, [{
29 | key: 'getDb',
30 | value: function getDb() {
31 | return this.db;
32 | }
33 | }, {
34 | key: 'set',
35 | value: function set(key, value) {
36 | if (key) {
37 | this.db[key] = value;
38 |
39 | return this._saveToLocalStorage();
40 | }
41 |
42 | throw new Error('set参数key不能为空');
43 | }
44 | }, {
45 | key: 'get',
46 | value: function get(key) {
47 | if (key) {
48 | var value = this.db[key];
49 | if (typeof value === 'undefined') {
50 | console.warn(key + '的值不存在');
51 | }
52 | return value;
53 | }
54 |
55 | throw new Error('get参数key不能为空');
56 | }
57 | }, {
58 | key: 'clean',
59 | value: function clean() {
60 | this.db = {};
61 | this._saveToLocalStorage();
62 | }
63 | }, {
64 | key: '_saveToLocalStorage',
65 | value: function _saveToLocalStorage() {
66 | localStorage[this.localDb] = JSON.stringify(this.getDb());
67 | }
68 | }]);
69 |
70 | return LocalDb;
71 | })();
72 |
73 | module.exports = LocalDb;
74 |
--------------------------------------------------------------------------------
/todoMvc/todoMvc-1step/README.md:
--------------------------------------------------------------------------------
1 | ### 如何用webpack搭建react+stylus项目
2 | 学习必要条件:略懂`node.js`,略懂`ES6`,然后你的电脑**必须**安装有较新版本[node](https://nodejs.org/en/download/),没有的同学赶紧安装。
3 | 好了,废话不多说,直接开始。
4 |
5 | 第一部分源码:[todoMvc-1step](https://github.com/Zegendary/react-demo/tree/master/todoMvc/todoMvc-1step)
6 | #[webpack](https://webpack.github.io/docs/what-is-webpack.html)的配置
7 | 1. 介绍:[Webpack](https://github.com/webpack/webpack) 是当下最热门的前端资源模块化管理和打包工具。详细见官网
8 | 2. 安装:
9 |
10 | $ npm install webpack -g
11 |
12 | 此时 Webpack 已经安装到了全局环境下,可以通过命令行 webpack -h 试试。
13 |
14 | 但通常我们会将 Webpack 以及相关依赖以这种方式安装,如下:
15 |
16 | # 进入项目目录
17 | # 确定已经有 package.json,没有就通过 npm init 创建
18 | # 安装 webpack 依赖
19 | $ npm install webpack --save-dev
20 | # 安装react.js依赖(i是install的简写,-S是--save的简写)
21 | $ npm i react react-dom -S
22 |
23 | 剩余的依赖组件参照我源码中的package.json的依赖添加就好。最终,我们得到的package.json应该如下图:
24 | 
25 | 确保红框中的内容一样即可。
26 |
27 | 3. 配置
28 |
29 | 现在我们已经安装好了依赖,下面我们需要先把项目的目录建好:
30 |
31 | .
32 | ├── node_modules # npm install 安装的东西都跑着里面来了
33 | ├── src
34 | ├── components
35 | ├── app.js # react组件
36 | ├── styles
37 | ├── main.styl # stylus文件(类似于sass)
38 | ├── entry.js # 入口js文件
39 | ├── index.html # 入口页面
40 | ├── package.json # 项目描述文件(内有相关依赖)
41 | └── webpack.config.js # webpack配置文件
42 |
43 | 然后我们在webpack.config.js中添加配置:
44 |
45 | module.exports = {
46 | entry: [
47 | "./src/entry.js"
48 | ],
49 | output: {
50 | path: './out/',
51 | filename: "bundle.js"
52 | },
53 | module: {
54 | loaders: [
55 | { test: /\.js[x]?$/, loader: "babel-loader?presets[]=es2015&presets[]=react", include: /src/},
56 | { test: /\.css$/, loader: "style!css"},
57 | { test: /\.styl$/, loader: "style-loader!css-loader!stylus-loader"},
58 | { test: /\.(png|jpg)$/, loader: 'url?limit=8192'}
59 | ]
60 | }
61 | }
62 |
63 | 配置文件将我们的入口文件`entry.js`打包输出到 `./out/bundle.js`,我们直接在页面`index.html`中引入`bundle.js`就好了
64 |
65 |
66 |
67 | 不懂得话可以参考webpack的文档:[webpack-usage](https://webpack.github.io/docs/usage.html) 和 [webpack-loader](https://webpack.github.io/docs/using-loaders.html)
68 |
69 | 关于`/src`目录下的文件内容可以直接到源码中查看。
70 | 然后就可以小试牛刀啦,在终端中输入:
71 |
72 | $ webpack
73 |
74 | 然后我们看到我们的目录下多了个`./out/bundle.js`文件,然后我们在浏览器打开目录下的index.html文件可以看到内容并alert('success')
75 | 
76 |
77 | 那么恭喜你,第一步圆满完成!
78 |
79 | [React+webpack从0到1开发一个todoMvc(二)](http://www.jianshu.com/p/ed01cf27b23d)
80 | [React+webpack从0到1开发一个todoMvc(三)](http://www.jianshu.com/p/80e54fc179e4)
81 | [React+webpack从0到1开发一个todoMvc(四)](http://www.jianshu.com/p/4b3b2f3146e2)
82 | [React+webpack从0到1开发一个todoMvc(五)](http://www.jianshu.com/p/86b83192917d)
--------------------------------------------------------------------------------
/todoMvc/todoMvc-2step/README.md:
--------------------------------------------------------------------------------
1 | #React如何双向绑定
2 | [todoMvc-2step源码](https://github.com/Zegendary/react-demo/tree/master/todoMvc/todoMvc-2step)
3 | [todoMvc-2step演示](https://zegendary.github.io/react-demo/todoMvc/todoMvc-2step/)
4 | 上一章主要说了下react+webpack的环境搭建,这一章主要讲一下如何双向绑定。对vue和angular略有了解的都知道,这两个框架都是支持双向绑定的,而react是单向绑定的,知乎有一篇关于单向绑定和双向绑定可以拓展一下:[单向数据绑定和双向数据绑定的优缺点,适合什么场景?](https://www.zhihu.com/question/49964363)
5 |
6 | ##下面分析如何具体实现
7 | 进入我们的`app.js`文件,在之前我们搭建环境的时候已经安装了react相关的依赖以及babel编译工具,所以我们可以直接在这里使用`ES6`、`JSX`语法。
8 | ####1.引入react核心内容
9 |
10 | import React from 'react'
11 | import ReactDOM from 'react-dom'
12 | 其中,react.js 是 React 的核心库,react-dom.js 是提供与 DOM 相关的功能。
13 |
14 | ####2.生成组件
15 | 先介绍react三个比较重要的知识点:
16 | 1)ReactDOM.render()
17 | ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。举个例子:
18 |
19 | ReactDOM.render(
20 | Hello, world! ,
21 | document.getElementById('example')
22 | );
23 | 上面代码将一个 h1 标题,插入 example 节点。
24 | 2)JSX 语法
25 | HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 [JSX 的语法](http://facebook.github.io/react/docs/displaying-data.html#jsx-syntax),它允许 HTML 与 JavaScript 的混写,上面的`Hello, world! `,就是使用了jsx语法。
26 | 3)组件
27 | React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类。举个🌰:
28 |
29 | #es5写法
30 | var HelloMessage = React.createClass({
31 | render: function() {
32 | return Hello React ;
33 | }
34 | });
35 | #es6写法
36 | Class HelloMessage extends React.Component {
37 | render() {
38 | return Hello, React;
39 | }
40 | }
41 | 当然,这里的`HelloMessage`我们也可以当做HTML标签用`ReactDOM.render()`渲染出来。
42 |
43 | `app.js`:
44 |
45 | class App extends React.Component { //定义组件,继承父类
46 | constructor() {//constructor 是和 class 一起用来创建和初始化对象的特殊方法。
47 | super()//在装载组件(mounting)之前调用会React组件的构造函数。当实现React.Component子类的构造函数时,应该在任何其他语句之前调用super(props)
48 | this.state = {//设置初始状态
49 | todos: []
50 | }
51 | }
52 | // 绑定键盘回车事件,添加新任务
53 | handlerKeyUp(e) {
54 | if(e.keyCode == 13) {
55 | let value = e.target.value;
56 | if(!value) return false;
57 | let newTodoItem = {
58 | text: value,
59 | isDone: false
60 | };
61 | e.target.value = '';
62 | this.state.todos.push(newTodoItem)
63 | this.setState({todos: this.state.todos}); //修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。
64 | }
65 | }
66 | render(){
67 | return (
68 |
69 |
70 |
71 | {this.state.todos.map((todo,index) => {{
72 | return (
73 | {todo.text} //Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity
74 | )
75 | }})}
76 |
77 |
78 | )
79 | }
80 | }
81 | ReactDOM.render( ,document.getElementById('app'))
82 |
83 | ####3.测试
84 | 运行
85 |
86 | $ webpack
87 | 然后打开`index.html`,如果可以在input输入,按下回车可以在下方生成list
88 |
89 | 那么恭喜你,双向绑定功能圆满完成!
90 |
91 | [React+webpack从0到1开发一个todoMvc(一)](http://www.jianshu.com/p/aa02a10c5b69)
92 | [React+webpack从0到1开发一个todoMvc(三)](http://www.jianshu.com/p/80e54fc179e4)
93 | [React+webpack从0到1开发一个todoMvc(四)](http://www.jianshu.com/p/4b3b2f3146e2)
94 | [React+webpack从0到1开发一个todoMvc(五)](http://www.jianshu.com/p/86b83192917d)
--------------------------------------------------------------------------------
/todoMvc/todoMvc-3step/README.md:
--------------------------------------------------------------------------------
1 | [todoMvc-3step源码](https://github.com/Zegendary/react-demo/tree/master/todoMvc/todoMvc-3step)
2 |
3 | [todoMvc-3step演示](https://zegendary.github.io/react-demo/todoMvc/todoMvc-3step/)
4 |
5 | 上一张主要介绍了下React如何进行双向绑定以及如何生成一个组件,我们第三步的目标就是需要把之前做的内容抽象出更细的组件,这样便于解耦,各个组件各司其职,互不干扰。
6 |
7 | 先看下抽象后`src/components`下的目录
8 |
9 | 
10 |
11 | 这是我们`app.js`修改过后的内容:
12 |
13 | import React from 'react'
14 | import ReactDOM from 'react-dom'
15 | import TodoHeader from './TodoHeader' // 引入TodoHeader组件
16 | import TodoMain from './TodoMain' // 引入TodoMain组件
17 |
18 | class App extends React.Component { // 定义组件,继承父类
19 | constructor() {
20 | super()
21 | this.state = {
22 | todos: []
23 | }
24 | }
25 | addTodo(item) { // 新增了添加todo事项的方法
26 | this.state.todos.push(item)
27 | this.setState({todos: this.state.todos}); //设置状态
28 | }
29 | render(){
30 | return (
31 |
32 | // 将原内容写在组件中并引入进行渲染
33 | // 把addTodo方法传递到TodoHeader组件中,bind(this)是为了把该React实例绑定到this上
34 |
35 | // 把 state.todos 传入到TodoMain 中
36 |
37 |
38 | )
39 | }
40 | }
41 |
42 | ReactDOM.render( ,document.getElementById('app'))
43 |
44 | `TodoHeader`:
45 |
46 | import React from 'react'
47 |
48 | class TodoHeader extends React.Component {
49 | // 绑定键盘回车事件,添加新任务
50 | handlerKeyUp(e) {
51 | if(e.keyCode == 13) { // enter键的 keyCode 为13
52 | let value = e.target.value;
53 | if(!value) return false;
54 | let newTodoItem = {
55 | text: value,
56 | isDone: false
57 | };
58 | e.target.value = '';
59 | this.props.addTodo(newTodoItem) // 通过 this.props 来调用父组件传递过来的addTodo方法
60 | }
61 | }
62 | render(){
63 | return (
64 |
65 |
66 |
67 | )
68 | }
69 | }
70 | export default TodoHeader // 将TodoHeader导出,否则父组件无法导入
71 | `TodoMain`修改后内容:
72 |
73 | import React from 'react'
74 | import TodoItem from './TodoItem'
75 |
76 | class TodoMain extends React.Component {
77 | render(){
78 | if(this.props.todos.length == 0) {
79 | return (
80 | 恭喜您,目前没有待办任务
81 | )
82 | } else {
83 | return (
84 |
85 | {
86 | this.props.todos.map((todo,index) => {
87 | //{...this.props} 用来传递TodoMain的todos属性和delete、change方法。
88 | return
89 | })
90 | }
91 |
92 | )
93 | }
94 | }
95 | }
96 | export default TodoMain
97 | `TodoItem`:
98 |
99 | import React from 'react'
100 |
101 | class TodoItem extends React.Component {
102 | render() {
103 | let className = this.props.isDone?'task-done':''
104 | return (
105 |
106 |
107 |
108 | {this.props.text}
109 |
110 |
111 | )
112 | }
113 | }
114 |
115 | export default TodoItem
116 | `TodoFoot`我们下章在做.
117 |
118 | 这一步时`webpack`先编译,然后打开index.html,如果页面像下图这样的[odoMvc-3step演示](https://zegendary.github.io/react-demo/todoMvc/todoMvc-3step/),那就说明成功了。
119 |
120 | 
121 |
122 | 做到这里应该对react组件组件化的有个大概的了解了。新手们基本可以对着源码按照这种思路继续做下去。以完善【删除】、【清除已完成】、【未完成数量】等功能了,由于代码类似,故不做赘述了,不太清楚的地方可以参考源码。
123 |
124 | [React+webpack从0到1开发一个todoMvc(一)](http://www.jianshu.com/p/aa02a10c5b69)
125 | [React+webpack从0到1开发一个todoMvc(二)](http://www.jianshu.com/p/ed01cf27b23d)
126 | [React+webpack从0到1开发一个todoMvc(四)](http://www.jianshu.com/p/4b3b2f3146e2)
127 | [React+webpack从0到1开发一个todoMvc(五)](http://www.jianshu.com/p/86b83192917d)
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/README.md:
--------------------------------------------------------------------------------
1 | [todoMvc-5step源码](https://github.com/Zegendary/react-demo/tree/master/todoMvc/todoMvc-5step)
2 | [todoMvc-5step演示](https://zegendary.github.io/react-demo/todoMvc/todoMvc-5step/)
3 |
4 | 这一章主要将上一章已经成型的TodoMvc增加【注册】、【登陆】、【数据储存】的功能,这里我们把数据保存到[leancloud](https://leancloud.cn/)。
5 |
6 | ### 1.创建 LeanCloud 账户
7 | 你需要去 [https://leancloud.cn](https://leancloud.cn/) 创建一个账户。
8 | 创建成功后,你需要验证你的邮箱,否则无法创建应用。
9 |
10 | ### 2.创建TodoMVC应用
11 | 如下图操作:
12 | 
13 | 创建成功后就放在那里,因为接下来我们要按照 LeanCloud 的「[JavaScript SDK 文档](https://leancloud.cn/docs/sdk_setup-js.html)」来开发登录、注册功能。
14 |
15 | ### 3.准备HTML页面
16 | 登陆和注册的页面同样也以组件的形式单独抽离出来,样式如图:
17 |
18 | 
19 | 组件`Login.js`代码如下:
20 |
21 | import React from 'react'
22 | import { Form, Icon, Input, Button } from 'antd';
23 |
24 | const FormItem = Form.Item;
25 |
26 | const Login = Form.create()(React.createClass({
27 | handleSubmit(e) { // 提交操作
28 | e.preventDefault();
29 | this.props.form.validateFields((err, values) => {
30 | if (!err) {
31 | this.props.loginOrSignUp(values)
32 | }
33 | });
34 | },
35 | render() {
36 | const { getFieldDecorator } = this.props.form;
37 | let text = this.props.value == 1 ?'注册':'登陆' // 判断“登陆”或者注册功能
38 | return (
39 |
60 | );
61 | },
62 | }));
63 | export default Login
64 | 在`app.js`中做判断,如果**已登录**,则显示ToDo应用界面,否则显示登陆界面:
65 |
66 | render(){
67 | if (!this.state.currentUser){ // 判断是否已经登录
68 | const RadioGroup = Radio.Group;
69 | return (
70 |
71 |
React-Todos
72 |
73 | 注册
74 | 登入
75 |
76 |
77 |
78 | )
79 | } else {
80 | let info = {
81 | isAllChecked: this.state.isAllChecked,
82 | todoCount: this.state.todos.length || 0,
83 | todoDoneCount: (this.state.todos && this.state.todos.filter((todo) => todo.isDone)).length || 0
84 | }
85 | return (
86 |
87 |
88 |
89 |
90 |
91 | )
92 | }
93 | }
94 |
95 | ### 4.注册&登陆
96 | 1.安装 LeanCloud SDK
97 |
98 | [https://leancloud.cn/docs/sdk_setup-js.html](https://leancloud.cn/docs/sdk_setup-js.html)
99 |
100 | $ npm install leancloud-storage --save
101 | 2.初始化
102 |
103 | [https://leancloud.cn/docs/sdk_setup-js.html#初始化](https://leancloud.cn/docs/sdk_setup-js.html#%E5%88%9D%E5%A7%8B%E5%8C%96)
104 | `app.js`:
105 |
106 | import AV from 'leancloud-storage'
107 |
108 | const appId = 'XXXXXXXXXXXXXXXXXXXXXX' //这里的appId就是刚才我们创建的应用的Id,每个人都不一样
109 | const appKey = 'XXXXXXXXXXXXXXXXXXX';
110 | AV.init({ appId, appKey });
111 | 3.写入注册登陆的方法
112 | 我们先要通读一下 LeanCloud [关于注册的文档](https://leancloud.cn/docs/leanstorage_guide-js.html#%E7%94%A8%E6%88%B7%E5%90%8D%E5%92%8C%E5%AF%86%E7%A0%81%E6%B3%A8%E5%86%8C),然后按照里面的demo去做修改。
113 | `app.js`:
114 |
115 | //登陆或者注册
116 | loginOrSignUp(values){
117 | //判断是登陆还是注册
118 | if (this.state.value === 1){
119 | let user = new AV.User();
120 | user.setUsername(values.userName);
121 | user.setPassword(values.password);
122 | user.signUp().then((loginedUser) => {
123 | this.state.currentUser = this.getCurrentUser()
124 | this.setState({currentUser: this.state.currentUser})
125 | }, function (error) {
126 | alert("注册失败")
127 | })
128 | } else if (this.state.value === 2){
129 | console.log("执行登陆")
130 | AV.User.logIn(values.userName, values.password).then((loginedUser) => {
131 | this.state.currentUser = this.getCurrentUser()
132 | this.setState({currentUser: this.state.currentUser})
133 | this.fetchTodos()
134 | }, function (error) {
135 | alert("登陆失败")
136 | });
137 | }
138 | }
139 |
140 | 下面还需要去做【登出】、【保存Todo】等功能。这里我就不贴出来代码了,可以直接去github上面去看我的[app.js源码](https://github.com/Zegendary/react-demo/blob/master/todoMvc/todoMvc-5step/src/components/app.js)。
141 | 至此,我们React+Webpack+Antd 的一个TodoMVC就开发完毕了。希望能帮助小伙伴。
142 |
143 | [React+webpack从0到1开发一个todoMvc(一)](http://www.jianshu.com/p/aa02a10c5b69)
144 | [React+webpack从0到1开发一个todoMvc(二)](http://www.jianshu.com/p/ed01cf27b23d)
145 | [React+webpack从0到1开发一个todoMvc(三)](http://www.jianshu.com/p/80e54fc179e4)
146 | [React+webpack从0到1开发一个todoMvc(四)](http://www.jianshu.com/p/4b3b2f3146e2)
--------------------------------------------------------------------------------
/todoMvc/todoMvc-5step/src/components/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by zhangxinwang on 16/02/2017.
3 | */
4 | import React from 'react'
5 | import ReactDOM from 'react-dom'
6 |
7 | import TodoHeader from './TodoHeader'
8 | import TodoMain from './TodoMain'
9 | import TodoFooter from './TodoFooter'
10 | import Login from './Login'
11 | import { Radio } from 'antd';
12 | import AV from 'leancloud-storage'
13 |
14 | const appId = 'VU2Q5GFPX9GzaOOQ0ka4pIOa-gzGzoHsz';
15 | const appKey = 'lE8CkfPRCgSBApNu3zmKUGht';
16 | AV.init({ appId, appKey });
17 |
18 | class App extends React.Component { //定义组件,继承父类
19 | constructor() {
20 | super()
21 | this.state = {
22 | todos: [],
23 | todoId: null,
24 | isAllChecked: false,
25 | currentUser: null,
26 | value: 1,
27 | }
28 | }
29 | //添加todoitem
30 | addTodo(item) {
31 | this.state.todos.push(item)
32 | this.setState({todos: this.state.todos}); //设置状态
33 | }
34 | // 改变任务状态,传递给TodoItem和Footer组件的方法
35 | changeTodoState(index, isDone, isChangeAll=false){ //初始化isChangeAll为false
36 | if(isChangeAll){ //全部操作
37 | this.setState({
38 | todos: this.state.todos.map((todo) => {
39 | todo.isDone = isDone;
40 | return todo;
41 | }),
42 | isAllChecked: isDone
43 | });
44 | }else{ //操作其中一个todo
45 | this.state.todos[index].isDone = isDone;
46 | this.allChecked();
47 | }
48 | }
49 | // 判断是否所有任务的状态都完成,同步底部的全选框
50 | allChecked() {
51 | let isAllChecked = false;
52 | if (this.state.todos.every(todo => todo.isDone)) {
53 | isAllChecked = true;
54 | }
55 | this.setState({ //改变状态,组件重绘
56 | todos: this.state.todos,
57 | isAllChecked: isAllChecked
58 | });
59 | }
60 | //清除已经完成事件
61 | clearDone(){
62 | let todos = this.state.todos.filter(todo => !todo.isDone)
63 | this.setState({
64 | todos : todos
65 | })
66 | }
67 | //删除某个todoitem
68 | deleteTodo(index) {
69 | this.state.todos.splice(index,1)
70 | this.setState({todos: this.state.todos})
71 | }
72 | //修改登录或者注册
73 | onChange(e) {
74 | this.setState({
75 | value: e.target.value,
76 | });
77 | }
78 | //登陆或者注册
79 | loginOrSignUp(values){
80 | //判断是登陆还是注册
81 | if (this.state.value === 1){
82 | let user = new AV.User();
83 | user.setUsername(values.userName);
84 | user.setPassword(values.password);
85 | user.signUp().then((loginedUser) => {
86 | this.state.currentUser = this.getCurrentUser()
87 | this.setState({currentUser: this.state.currentUser})
88 | }, function (error) {
89 | alert("注册失败")
90 | })
91 | } else if (this.state.value === 2){
92 | console.log("执行登陆")
93 | AV.User.logIn(values.userName, values.password).then((loginedUser) => {
94 | this.state.currentUser = this.getCurrentUser()
95 | this.setState({currentUser: this.state.currentUser})
96 | this.fetchTodos()
97 | }, function (error) {
98 | alert("登陆失败")
99 | });
100 | }
101 | }
102 | //获取当前用户
103 | getCurrentUser() {
104 | let current = AV.User.current()
105 | if (current){
106 | let {id, createdAt, attributes: {username}} = current
107 | return {id, username, createdAt}
108 | } else{
109 | return null
110 | }
111 | }
112 | //登出用户
113 | logout() {
114 | AV.User.logOut()
115 | this.state.currentUser = null
116 | window.location.reload()
117 | }
118 | //将todo储存到服务器上
119 | saveTodos() {
120 | let dataString = JSON.stringify(this.state.todos)
121 | var AVTodos = AV.Object.extend('AllTodos');
122 | var avTodos = new AVTodos();
123 | // 新建一个 ACL 实例
124 | var acl = new AV.ACL();
125 | acl.setReadAccess(AV.User.current(),true)
126 | acl.setWriteAccess(AV.User.current(),true)
127 |
128 | avTodos.setACL(acl) // 设置访问控制
129 |
130 | avTodos.set('content', dataString);
131 | avTodos.save().then((todo) => {
132 | this.state.todoId = todo.id
133 | this.setState({todoId:this.state.todoId})
134 | console.log('保存成功');
135 | }, function (error) {
136 | // 异常处理
137 | console.log('保存失败');
138 | });
139 | }
140 | //更新todo到服务器上
141 | updateTodos() {
142 | let dataString = JSON.stringify(this.state.todos)
143 | let avTodos = AV.Object.createWithoutData('AllTodos', this.state.todoId)
144 | avTodos.set('content', dataString)
145 | avTodos.save().then(()=>{
146 | console.log('更新成功')
147 | })
148 | }
149 | //判断应该更新或储存list到leanCloud
150 | saveOrUpdateTodos() {
151 | if(this.state.todoId){
152 | this.updateTodos()
153 | } else {
154 | this.saveTodos()
155 | }
156 | }
157 | componentWillMount() {
158 | this.state.currentUser = this.getCurrentUser()
159 | this.fetchTodos()
160 | this.setState({currentUser: this.state.currentUser})
161 | }
162 | fetchTodos() {
163 | if(this.state.currentUser){
164 | var query = new AV.Query('AllTodos');
165 | query.find()
166 | .then((todoList) => {
167 | let avAllTodos = todoList[0]// 因为理论上 AllTodos 只有一个,所以我们取结果的第一项
168 | let id = avAllTodos.id
169 | this.state.todos = JSON.parse(avAllTodos.attributes.content)
170 | this.state.todoId = id
171 | this.setState({todos:this.state.todos,todoId:this.state.todoId})
172 | }, function(error){
173 | console.error(error)
174 | })
175 | }
176 | }
177 | render(){
178 | if (!this.state.currentUser){
179 | const RadioGroup = Radio.Group;
180 | return (
181 |
182 |
React-Todos
183 |
184 | 注册
185 | 登入
186 |
187 |
188 |
189 | )
190 | } else {
191 | let info = {
192 | isAllChecked: this.state.isAllChecked,
193 | todoCount: this.state.todos.length || 0,
194 | todoDoneCount: (this.state.todos && this.state.todos.filter((todo) => todo.isDone)).length || 0
195 | }
196 | return (
197 |
198 |
199 |
200 |
201 |
202 | )
203 | }
204 | }
205 | }
206 |
207 |
208 | ReactDOM.render( ,document.getElementById('app'))
--------------------------------------------------------------------------------
/todoMvc/todoMvc-1step/out/bundle.js:
--------------------------------------------------------------------------------
1 | /******/ (function(modules) { // webpackBootstrap
2 | /******/ // The module cache
3 | /******/ var installedModules = {};
4 |
5 | /******/ // The require function
6 | /******/ function __webpack_require__(moduleId) {
7 |
8 | /******/ // Check if module is in cache
9 | /******/ if(installedModules[moduleId])
10 | /******/ return installedModules[moduleId].exports;
11 |
12 | /******/ // Create a new module (and put it into the cache)
13 | /******/ var module = installedModules[moduleId] = {
14 | /******/ i: moduleId,
15 | /******/ l: false,
16 | /******/ exports: {}
17 | /******/ };
18 |
19 | /******/ // Execute the module function
20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21 |
22 | /******/ // Flag the module as loaded
23 | /******/ module.l = true;
24 |
25 | /******/ // Return the exports of the module
26 | /******/ return module.exports;
27 | /******/ }
28 |
29 |
30 | /******/ // expose the modules object (__webpack_modules__)
31 | /******/ __webpack_require__.m = modules;
32 |
33 | /******/ // expose the module cache
34 | /******/ __webpack_require__.c = installedModules;
35 |
36 | /******/ // identity function for calling harmony imports with the correct context
37 | /******/ __webpack_require__.i = function(value) { return value; };
38 |
39 | /******/ // define getter function for harmony exports
40 | /******/ __webpack_require__.d = function(exports, name, getter) {
41 | /******/ if(!__webpack_require__.o(exports, name)) {
42 | /******/ Object.defineProperty(exports, name, {
43 | /******/ configurable: false,
44 | /******/ enumerable: true,
45 | /******/ get: getter
46 | /******/ });
47 | /******/ }
48 | /******/ };
49 |
50 | /******/ // getDefaultExport function for compatibility with non-harmony modules
51 | /******/ __webpack_require__.n = function(module) {
52 | /******/ var getter = module && module.__esModule ?
53 | /******/ function getDefault() { return module['default']; } :
54 | /******/ function getModuleExports() { return module; };
55 | /******/ __webpack_require__.d(getter, 'a', getter);
56 | /******/ return getter;
57 | /******/ };
58 |
59 | /******/ // Object.prototype.hasOwnProperty.call
60 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
61 |
62 | /******/ // __webpack_public_path__
63 | /******/ __webpack_require__.p = "";
64 |
65 | /******/ // Load entry module and return exports
66 | /******/ return __webpack_require__(__webpack_require__.s = 6);
67 | /******/ })
68 | /************************************************************************/
69 | /******/ ([
70 | /* 0 */
71 | /***/ (function(module, exports, __webpack_require__) {
72 |
73 | "use strict";
74 |
75 |
76 | __webpack_require__(1);
77 | __webpack_require__(5);
78 |
79 | /***/ }),
80 | /* 1 */
81 | /***/ (function(module, exports, __webpack_require__) {
82 |
83 | "use strict";
84 |
85 |
86 | /**
87 | * Created by zhangxinwang on 16/02/2017.
88 | */
89 | alert('success');
90 |
91 | /***/ }),
92 | /* 2 */
93 | /***/ (function(module, exports, __webpack_require__) {
94 |
95 | exports = module.exports = __webpack_require__(3)();
96 | exports.push([module.i, ".todo-title {\n color: #f00;\n}\n", ""]);
97 |
98 | /***/ }),
99 | /* 3 */
100 | /***/ (function(module, exports) {
101 |
102 | /*
103 | MIT License http://www.opensource.org/licenses/mit-license.php
104 | Author Tobias Koppers @sokra
105 | */
106 | // css base code, injected by the css-loader
107 | module.exports = function() {
108 | var list = [];
109 |
110 | // return the list of modules as css string
111 | list.toString = function toString() {
112 | var result = [];
113 | for(var i = 0; i < this.length; i++) {
114 | var item = this[i];
115 | if(item[2]) {
116 | result.push("@media " + item[2] + "{" + item[1] + "}");
117 | } else {
118 | result.push(item[1]);
119 | }
120 | }
121 | return result.join("");
122 | };
123 |
124 | // import a list of modules into the list
125 | list.i = function(modules, mediaQuery) {
126 | if(typeof modules === "string")
127 | modules = [[null, modules, ""]];
128 | var alreadyImportedModules = {};
129 | for(var i = 0; i < this.length; i++) {
130 | var id = this[i][0];
131 | if(typeof id === "number")
132 | alreadyImportedModules[id] = true;
133 | }
134 | for(i = 0; i < modules.length; i++) {
135 | var item = modules[i];
136 | // skip already imported module
137 | // this implementation is not 100% perfect for weird media query combinations
138 | // when a module is imported multiple times with different media queries.
139 | // I hope this will never occur (Hey this way we have smaller bundles)
140 | if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
141 | if(mediaQuery && !item[2]) {
142 | item[2] = mediaQuery;
143 | } else if(mediaQuery) {
144 | item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
145 | }
146 | list.push(item);
147 | }
148 | }
149 | };
150 | return list;
151 | };
152 |
153 |
154 | /***/ }),
155 | /* 4 */
156 | /***/ (function(module, exports) {
157 |
158 | /*
159 | MIT License http://www.opensource.org/licenses/mit-license.php
160 | Author Tobias Koppers @sokra
161 | */
162 | var stylesInDom = {},
163 | memoize = function(fn) {
164 | var memo;
165 | return function () {
166 | if (typeof memo === "undefined") memo = fn.apply(this, arguments);
167 | return memo;
168 | };
169 | },
170 | isOldIE = memoize(function() {
171 | return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
172 | }),
173 | getHeadElement = memoize(function () {
174 | return document.head || document.getElementsByTagName("head")[0];
175 | }),
176 | singletonElement = null,
177 | singletonCounter = 0;
178 |
179 | module.exports = function(list, options) {
180 | if(typeof DEBUG !== "undefined" && DEBUG) {
181 | if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
182 | }
183 |
184 | options = options || {};
185 | // Force single-tag solution on IE6-9, which has a hard limit on the # of