React+webpack+Antd從0到1開發一個todoMvc

首先咱們看一下咱們完成後的最終形態:TodoMvccss

TodoMVc

學習必要條件:略懂node.js,略懂ES6,而後你的電腦必須安裝有較新版本node,沒有的同窗趕忙安裝。
好了,廢話很少說,直接開始。html

第一部分源碼:todoMvc-1step前端

webpack的配置

1. 介紹:

Webpack 是當下最熱門的前端資源模塊化管理和打包工具。詳細見官網vue

2. 安裝:

$ 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應該以下圖:package.json確保紅框中的內容同樣便可。react

3. 配置

如今咱們已經安裝好了依賴,下面咱們須要先把項目的目錄建好: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-usagewebpack-loader。關於/src目錄下的文件內容能夠直接到源碼中查看。而後就能夠小試牛刀啦,在終端中輸入:github

$ webpack

而後咱們看到咱們的目錄下多了個./out/bundle.js文件,而後咱們在瀏覽器打開目錄下的index.html文件能夠看到內容並alert('success')todoMvc-step1那麼恭喜你,第一步圓滿完成!

React如何雙向綁定

todoMvc-2step源碼
todoMvc-2step演示
上一章主要說了下react+webpack的環境搭建,這一章主要講一下如何雙向綁定。對vue和angular略有了解的都知道,這兩個框架都是支持雙向綁定的,而react是單向綁定的,知乎有一篇關於單向綁定和雙向綁定能夠拓展一下:單向數據綁定和雙向數據綁定的優缺點,適合什麼場景。下面分析如何具體實現:
進入咱們的app.js文件,在以前咱們搭建環境的時候已經安裝了react相關的依賴以及babel編譯工具,因此咱們能夠直接在這裏使用ES6JSX語法。

1. 引入react核心內容

import React from 'react'
import ReactDOM from 'react-dom'

其中,react.js 是 React 的核心庫,react-dom.js 是提供與 DOM 相關的功能。

2. 生成組件

先介紹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'))

3. 測試

運行

$ 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組件組件化的有個大概的瞭解了。新手們基本能夠對着源碼按照這種思路繼續作下去。以完善【刪除】、【清除已完成】、【未完成數量】等功能了,因爲代碼相似,故不作贅述了,不太清楚的地方能夠參考源碼。

Antd

todoMvc-4step源碼
todoMvc-4step演示

這一章主要以【刪除】鍵爲例講一下如何使用以 React 封裝了一套 Ant Design 的組件庫:

Ant Design

1. 安裝

推薦使用 npm 的方式進行開發,不只可在開發環境輕鬆調試,也可放心地在生產環境打包部署使用,享受整個生態圈和工具鏈帶來的諸多好處。
能夠經過 npm 直接安裝到項目中,使用 importrequire 進行引用。

$ npm install antd --save

2. 加載

能夠經過如下的寫法來按需加載組件。

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組件,便可以下這麼寫以達到按需加載jscss

import { Button } from 'antd';

3. 使用

因爲Antd組件已經油React封裝好了,用法和原生html標籤沒差:

<Button type="danger" size="small" onClick={this.handlerDelete.bind(this)}>刪除</Button>

剩餘的樣式咱們就能夠對着antd components的demo來開發。

使用leancloud登陸註冊

todoMvc-5step源碼
todoMvc-5step演示

這一章主要將上一章已經成型的TodoMvc增長【註冊】、【登錄】、【數據儲存】的功能,這裏咱們把數據保存到leancloud

1. 建立 LeanCloud 帳戶

你須要去 https://leancloud.cn 建立一個帳戶。
建立成功後,你須要驗證你的郵箱,不然沒法建立應用。

2. 建立TodoMVC應用

以下圖操做:
建立應用
建立成功後就放在那裏,由於接下來咱們要按照 LeanCloud 的「JavaScript SDK 文檔」來開發登陸、註冊功能。

3. 準備HTML頁面

登錄和註冊的頁面一樣也以組件的形式單獨抽離出來,樣式如圖:

登陸註冊

組件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>
    )
  }
}

4. 註冊&登錄

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的思路就講解完畢了。但願能幫助小夥伴。

相關文章
相關標籤/搜索