首先咱們看一下咱們完成後的最終形態: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的思路就講解完畢了。但願能幫助小夥伴。