首先咱们看一下咱们完成后的最终形态:TodoMvc:css
学习必要条件:略懂node.js
,略懂ES6
,而后你的电脑必须安装有较新版本node,没有的同窗赶忙安装。
好了,废话很少说,直接开始。html
第一部分源码:todoMvc-1step前端
Webpack 是当下最热门的前端资源模块化管理和打包工具。详细见官网vue
$ npm install webpack -g
此时 Webpack 已经安装到了全局环境下,能够经过命令行 webpack -h 试试。但一般咱们会将 Webpack 以及相关依赖以这种方式安装,以下:node
# 进入项目目录 # 肯定已经有 package.json,没有就经过 npm init 建立 # 安装 webpack 依赖 $ npm install webpack --save-dev # 安装react.js依赖(i是install的简写,-S是--save的简写) $ npm i react react-dom -S
剩余的依赖组件参照我源码中的package.json的依赖添加就好。最终,咱们获得的package.json应该以下图:确保红框中的内容同样便可。react
如今咱们已经安装好了依赖,下面咱们须要先把项目的目录建好:webpack
. ├── node_modules # npm install 安装的东西都跑着里面来了 ├── src ├── components ├── app.js # react组件 ├── styles ├── main.styl # stylus文件(相似于sass) ├── entry.js # 入口js文件 ├── index.html # 入口页面 ├── package.json # 项目描述文件(内有相关依赖) └── webpack.config.js # webpack配置文件
而后咱们在webpack.config.js中添加配置:git
module.exports = { entry: [ "./src/entry.js" ], output: { path: './out/', filename: "bundle.js" }, module: { loaders: [ { test: /\.js[x]?$/, loader: "babel-loader?presets[]=es2015&presets[]=react", include: /src/}, { test: /\.css$/, loader: "style!css"}, { test: /\.styl$/, loader: "style-loader!css-loader!stylus-loader"}, { test: /\.(png|jpg)$/, loader: 'url?limit=8192'} ] } }
配置文件将咱们的入口文件entry.js
打包输出到 ./out/bundle.js
,咱们直接在页面index.html
中引入bundle.js
就行了。es6
<script src="./out/bundle.js"></script>
不懂得话能够参考webpack的文档:webpack-usage 和 webpack-loader。关于/src
目录下的文件内容能够直接到源码中查看。而后就能够小试牛刀啦,在终端中输入:github
$ webpack
而后咱们看到咱们的目录下多了个./out/bundle.js
文件,而后咱们在浏览器打开目录下的index.html文件能够看到内容并alert('success')
那么恭喜你,第一步圆满完成!
todoMvc-2step源码
todoMvc-2step演示
上一章主要说了下react+webpack的环境搭建,这一章主要讲一下如何双向绑定。对vue和angular略有了解的都知道,这两个框架都是支持双向绑定的,而react是单向绑定的,知乎有一篇关于单向绑定和双向绑定能够拓展一下:单向数据绑定和双向数据绑定的优缺点,适合什么场景。下面分析如何具体实现:
进入咱们的app.js
文件,在以前咱们搭建环境的时候已经安装了react相关的依赖以及babel编译工具,因此咱们能够直接在这里使用ES6
、JSX
语法。
import React from 'react' import ReactDOM from 'react-dom'
其中,react.js 是 React 的核心库,react-dom.js 是提供与 DOM 相关的功能。
先介绍react三个比较重要的知识点:
1.ReactDOM.render()
ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。举个例子:
ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('example') );
上面代码将一个 h1 标题,插入 example 节点。
2.JSX 语法
HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它容许 HTML 与 JavaScript 的混写,上面的<h1>Hello, world!</h1>
,就是使用了jsx语法。
3.组件
React 容许将代码封装成组件(component),而后像插入普通 HTML 标签同样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类。举个?:
//es5写法 var HelloMessage = React.createClass({ render: function() { return <h1>Hello React</h1>; } }); //es6写法 Class HelloMessage extends React.Component { render() { return <h1>Hello, React</hr>; } }
固然,这里的HelloMessage
咱们也能够当作HTML标签用ReactDOM.render()
渲染出来。
app.js
:
class App extends React.Component { //定义组件,继承父类 constructor() {//constructor 是和 class 一块儿用来建立和初始化对象的特殊方法。 super()//在装载组件(mounting)以前调用会React组件的构造函数。当实现React.Component子类的构造函数时,应该在任何其余语句以前调用super(props) this.state = {//设置初始状态 todos: [] } } // 绑定键盘回车事件,添加新任务 handlerKeyUp(e) { if(e.keyCode == 13) { let value = e.target.value; if(!value) return false; let newTodoItem = { text: value, isDone: false }; e.target.value = ''; this.state.todos.push(newTodoItem) this.setState({todos: this.state.todos}); //修改状态值,每次修改之后,自动调用 this.render 方法,再次渲染组件。 } } render(){ return ( <div className="todo-input"> <input type="text" placeholder="请输入待办事项" onKeyUp={this.handlerKeyUp.bind(this)}/> <ul> {this.state.todos.map((todo,index) => {{ return ( <li key={index}>{todo.text}</li>//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 ) }})} </ul> </div> ) } } ReactDOM.render(<App/>,document.getElementById('app'))
运行
$ webpack
而后打开index.html
,若是能够在input输入,按下回车能够在下方生成list
那么恭喜你,双向绑定功能完成!
todoMvc-3step源码
todoMvc-3step演示
上一章主要介绍了下React如何进行双向绑定以及如何生成一个组件,咱们第三步的目标就是须要把以前作的内容抽象出更细的组件,这样便于解耦,各个组件各司其职,互不干扰。
先看下抽象后src/components
下的目录
先看下咱们的app.js
修改事后的内容:
import React from 'react' import ReactDOM from 'react-dom' import TodoHeader from './TodoHeader' // 引入TodoHeader组件 import TodoMain from './TodoMain' // 引入TodoMain组件 class App extends React.Component { // 定义组件,继承父类 constructor() { super() this.state = { todos: [] } } addTodo(item) { // 新增了添加todo事项的方法 this.state.todos.push(item) this.setState({todos: this.state.todos}); //设置状态 } render(){ return ( <div className="todo-wrapper"> // 将原内容写在组件中并引入进行渲染 // 把addTodo方法传递到TodoHeader组件中,bind(this)是为了把该React实例绑定到this上 <TodoHeader addTodo={this.addTodo.bind(this)}/> // 把 state.todos 传入到TodoMain 中 <TodoMain todos={this.state.todos}/> </div> ) } } ReactDOM.render(<App/>,document.getElementById('app'))
TodoHeader
:
import React from 'react' class TodoHeader extends React.Component { // 绑定键盘回车事件,添加新任务 handlerKeyUp(e) { if(e.keyCode == 13) { // enter键的 keyCode 为13 let value = e.target.value; if(!value) return false; let newTodoItem = { text: value, isDone: false }; e.target.value = ''; this.props.addTodo(newTodoItem) // 经过 this.props 来调用父组件传递过来的addTodo方法 } } render(){ return ( <div className="todo-header"> <input onKeyUp={this.handlerKeyUp.bind(this)} type="text" placeholder="请输入你的任务名称,按回车键确认"/> </div> ) } } export default TodoHeader // 将TodoHeader导出,不然父组件没法导入
TodoMain
修改后内容:
import React from 'react' import TodoItem from './TodoItem' class TodoMain extends React.Component { render(){ if(this.props.todos.length == 0) { return ( <div className="todo-empty">恭喜您,目前没有待办任务</div> ) } else { return ( <ul className="todo-main"> { this.props.todos.map((todo,index) => { //{...this.props} 用来传递TodoMain的todos属性和delete、change方法。 return <TodoItem text={todo.text} isDone={todo.isDone} index={index} {...this.props} key={index}/> }) } </ul> ) } } } export default TodoMain
TodoItem
:
import React from 'react' class TodoItem extends React.Component { render() { let className = this.props.isDone?'task-done':'' return ( <li> <label> <input type="checkbox"/> <span className={className}>{this.props.text}</span> </label> </li> ) } } export default TodoItem
这一步时webpack
先编译,而后打开index.html,若是页面像下图这样的odoMvc-3step演示,那就说明成功了。
作到这里应该对react组件组件化的有个大概的了解了。新手们基本能够对着源码按照这种思路继续作下去。以完善【删除】、【清除已完成】、【未完成数量】等功能了,因为代码相似,故不作赘述了,不太清楚的地方能够参考源码。
todoMvc-4step源码
todoMvc-4step演示
这一章主要以【删除】键为例讲一下如何使用以 React 封装了一套 Ant Design 的组件库:
推荐使用 npm 的方式进行开发,不只可在开发环境轻松调试,也可放心地在生产环境打包部署使用,享受整个生态圈和工具链带来的诸多好处。
能够经过 npm 直接安装到项目中,使用 import
或 require
进行引用。
$ npm install antd --save
能够经过如下的写法来按需加载组件。
import Button from 'antd/lib/button'; import 'antd/lib/button/style'; // 或者 antd/lib/button/style/css 加载 css 文件
但我推荐使用更简便的写法:
首先须要安装babel-plugin-import 依赖
$ npm install babel-plugin-import --save-dev
而后在咱们的根目录下新建.babelrc
:
{ "plugins": [["import", {"libraryName": "antd", "style": "css"}]] //import js and css modularly }
这时咱们须要什么UI组件,便可以下这么写以达到按需加载js
和css
:
import { Button } from 'antd';
因为Antd
组件已经油React
封装好了,用法和原生html标签没差:
<Button type="danger" size="small" onClick={this.handlerDelete.bind(this)}>删除</Button>
剩余的样式咱们就能够对着antd components的demo来开发。
todoMvc-5step源码
todoMvc-5step演示
这一章主要将上一章已经成型的TodoMvc增长【注册】、【登录】、【数据储存】的功能,这里咱们把数据保存到leancloud。
你须要去 https://leancloud.cn 建立一个帐户。
建立成功后,你须要验证你的邮箱,不然没法建立应用。
以下图操做:
建立成功后就放在那里,由于接下来咱们要按照 LeanCloud 的「JavaScript SDK 文档」来开发登陆、注册功能。
登录和注册的页面一样也以组件的形式单独抽离出来,样式如图:
组件Login.js
代码以下:
import React from 'react' import { Form, Icon, Input, Button } from 'antd'; const FormItem = Form.Item; const Login = Form.create()(React.createClass({ handleSubmit(e) { // 提交操做 e.preventDefault(); this.props.form.validateFields((err, values) => { if (!err) { this.props.loginOrSignUp(values) } }); }, render() { const { getFieldDecorator } = this.props.form; let text = this.props.value == 1 ?'注册':'登录' // 判断“登录”或者注册功能 return ( <Form onSubmit={this.handleSubmit} className="login-form"> // antdUI的表单 <FormItem> {getFieldDecorator('userName', { rules: [{ required: true, message: 'Please input your username!' }], })( <Input addonBefore={<Icon type="user" />} placeholder="Username" /> )} </FormItem> <FormItem> {getFieldDecorator('password', { rules: [{ required: true, message: 'Please input your Password!' }], // 必须填写项 })( <Input addonBefore={<Icon type="lock" />} type="password" placeholder="Password" /> )} </FormItem> <FormItem> <Button type="primary" htmlType="submit" className="login-form-button"> {text} </Button> </FormItem> </Form> ); }, })); export default Login
在app.js
中作判断,若是已登陆,则显示ToDo应用界面,不然显示登录界面:
render(){ if (!this.state.currentUser){ // 判断是否已经登陆 const RadioGroup = Radio.Group; return ( <div className="form-wrapper"> <h1 className="todo-title">React-Todos</h1> <RadioGroup className="radio-wrapper" onChange={this.onChange.bind(this)} value={this.state.value}> <Radio value={1}>注册</Radio> <Radio value={2}>登入</Radio> </RadioGroup> <Login loginOrSignUp={this.loginOrSignUp.bind(this)} value={this.state.value}/> </div> ) } else { let info = { isAllChecked: this.state.isAllChecked, todoCount: this.state.todos.length || 0, todoDoneCount: (this.state.todos && this.state.todos.filter((todo) => todo.isDone)).length || 0 } return ( <div className="todo-wrapper"> <TodoHeader addTodo={this.addTodo.bind(this)} currentUser={this.state.currentUser} logout={this.logout.bind(this)}/> <TodoMain todos={this.state.todos} changeTodoState={this.changeTodoState.bind(this)} deleteTodo={this.deleteTodo.bind(this)} saveOrUpdateTodos={this.saveOrUpdateTodos.bind(this)}/> <TodoFooter {...info} clearDone={this.clearDone.bind(this)} changeTodoState={this.changeTodoState.bind(this)}/> </div> ) } }
1.安装 LeanCloud SDK
https://leancloud.cn/docs/sdk_setup-js.html
$ npm install leancloud-storage --save
2.初始化
https://leancloud.cn/docs/sdk_setup-js.html#初始化app.js
:
import AV from 'leancloud-storage' const appId = 'XXXXXXXXXXXXXXXXXXXXXX' //这里的appId就是刚才咱们建立的应用的Id,每一个人都不同 const appKey = 'XXXXXXXXXXXXXXXXXXX'; AV.init({ appId, appKey });
3.写入注册登录的方法
咱们先要通读一下 LeanCloud 关于注册的文档,而后按照里面的demo去作修改。app.js
:
//登录或者注册 loginOrSignUp(values){ //判断是登录仍是注册 if (this.state.value === 1){ let user = new AV.User(); user.setUsername(values.userName); user.setPassword(values.password); user.signUp().then((loginedUser) => { this.state.currentUser = this.getCurrentUser() this.setState({currentUser: this.state.currentUser}) }, function (error) { alert("注册失败") }) } else if (this.state.value === 2){ console.log("执行登录") AV.User.logIn(values.userName, values.password).then((loginedUser) => { this.state.currentUser = this.getCurrentUser() this.setState({currentUser: this.state.currentUser}) this.fetchTodos() }, function (error) { alert("登录失败") }); } }
下面还须要去作【登出】、【保存Todo】等功能。这里我就不贴出来代码了,能够直接去github上面去看个人app.js源码。至此,咱们React+Webpack+Antd 的一个TodoMVC的思路就讲解完毕了。但愿能帮助小伙伴。