• 577 React系列三


    一. 书籍购物车说明

    1.1. 案例介绍

    现在我们来做一个相对综合一点的练习:书籍购物车;

    案例效果如下:

    ~

    案例说明:

    • 1.在界面上以表格的形式,显示一些书籍的数据;
    • 2.在底部显示书籍的总价格;
    • 3.点击+或者-可以增加或减少书籍数量(如果为1,那么不能继续-);
    • 4.点击移除按钮,可以将书籍移除(当所有的书籍移除完毕时,显示:购物车为空~);

    1.2. 项目的搭建

    这里,我们使用React将默认的数据先展示出来:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    
      <style>
        table {
          border: 1px solid #e9e9e9;
          border-collapse: collapse;
        }
    
        td, th {
          border: 1px solid #e9e9e9;
          padding: 8px 16px;
        }
    
        th {
          background-color: #f7f7f7;
          color: #5c6b77;
        }
    
        .counter {
          margin: 0 5px;
        }
      </style>
    </head>
    <body>
        
      <div id="app"></div>
    
      <script src="../react/react.development.js"></script>
      <script src="../react/react-dom.development.js"></script>
      <script src="../react/babel.min.js"></script>
    
      <script type="text/babel">
        class App extends React.Component {
          constructor(props) {
            super(props);
            this.state = {
              books: [
                {
                  id: 1,
                  name: '《算法导论》',
                  date: '2006-9',
                  price: 85.00,
                  count: 1
                },
                {
                  id: 2,
                  name: '《UNIX编程艺术》',
                  date: '2006-2',
                  price: 59.00,
                  count: 1
                },
                {
                  id: 3,
                  name: '《编程珠玑》',
                  date: '2008-10',
                  price: 39.00,
                  count: 1
                },
                {
                  id: 4,
                  name: '《代码大全》',
                  date: '2006-3',
                  price: 128.00,
                  count: 1
                },
              ]
            }
          }
    
          render() {
            const { books } = this.state;
    
            return (
              <div>
                <table>
                  <thead>
                    <tr>
                      <th></th>
                      <th>书籍名称</th>
                      <th>出版日期</th>
                      <th>价格</th>
                      <th>购买数量</th>
                      <th>操作</th>
                    </tr>
                  </thead>
                  <tbody>
                    {
                      books.map((item, index) => {
                        return (
                          <tr>
                            <td>{index + 1}</td>
                            <td>{item.name}</td>
                            <td>{item.date}</td>
                            <td>{"¥" + item.price}</td>
                            <td>
                              <button>-</button>
                              <span className="counter">{item.count}</span>
                              <button>+</button>
                            </td>
                            <td><button>移除</button></td>
                          </tr>
                        )
                      })
                    }
                  </tbody>
                </table>
              </div>
            )
          }
        }
    
        ReactDOM.render(<App/>, document.getElementById("app"));
      </script>
    
    </body>
    </html>
    

    二. 书籍购物车功能

    1.1. 价格的显示

    我们可以封装一个工具函数,用于格式化价格:

    function formatPrice(price) {
      if (typeof price !== "number") {
        price = Number(price) || 0;
      }
      return "¥" + price.toFixed(2);
    }
    

    对之前显示的价格进行格式化:

    <td>{formatPrice(item.price)}</td>
    

    封装一个App中的方法,用于获取商品总价格显示的内容:

    getTotalPrice() {
      let totalPrice = 0;
      for (let book of this.state.books) {
        totalPrice += book.count * book.price
      }
      return "总价格:" + formatPrice(totalPrice);
    }
    

    使用一个h2元素显示总价格:

    <h2>  {this.getTotalPrice()}</h2>
    

    1.2. 数量的变化

    封装一个方法,用于改变书籍的数量:

    • 注意:在React中,要保证数据的不可变性;
    • 所以,我们是先复制一份books,对其进行修改,再通过setState更新到最新的状态;
    changeItem(index, counter) {
      const books = [...this.state.books];
      this.setState({
        books: books.map((item, indey) => {
          if (indey == index) {
            item.count += counter;
          }
          return item;
        })
      })
    }
    

    修改jsx对应位置的代码:

    <td>
      <button disabled={item.count <= 1} onClick={e => this.changeItem(index, -1)}>-</button>
      <span className="counter">{item.count}</span>
      <button onClick={e => this.changeItem(index, 1)}>+</button>
    </td>
    

    1.3. 移除的操作

    封装一个方法,用于移除对应的书籍:

    removeItem(index) {
      const books = [...this.state.books];
      this.setState({
        books: books.filter((item, indey) => index !== indey)
      })
    }
    

    修改对应的移除jsx代码:

    <td><button onClick={e => this.removeItem(index)}>移除</button></td>
    

    如果所有的书籍移除完毕,那么要显示购物车为空:

    • 封装两个方法,一个用于获取显示购物车的jsx代码(后期会封装成一个组件),一个用于获取显示购物车为空的jsx代码(后期也可以封装为一个组件)
    renderBooks() {
      const { books } = this.state;
      return (
        <div>
          <table>
            <thead>
              <tr>
                <th></th>
                <th>书籍名称</th>
                <th>出版日期</th>
                <th>价格</th>
                <th>购买数量</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
              {
                books.map((item, index) => {
                  return (
                    <tr>
                      <td>{index + 1}</td>
                      <td>{item.name}</td>
                      <td>{item.date}</td>
                      <td>{formatPrice(item.price)}</td>
                      <td>
                        <button>-</button>
                        <span className="counter">{item.count}</span>
                        <button>+</button>
                      </td>
                      <td><button onClick={e => this.removeItem(index)}>移除</button></td>
                    </tr>
                  )
                })
              }
            </tbody>
          </table>
          <h2>
            {this.getTotalPrice()}
          </h2>
        </div>
      )
    }
    
    renderEmpty() {
      return <h2>购物车为空~</h2>
    }
    

    重新编写render方法代码:

    render() {
      const { books } = this.state;
      return books.length ? this.renderBooks() : this.renderEmpty();
    }
    

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    
      <style>
        table {
          border: 1px solid #eee;
          border-collapse: collapse;
        }
    
        th,
        td {
          border: 1px solid #eee;
          padding: 10px 16px;
          text-align: center;
        }
    
        th {
          background-color: #ccc;
        }
    
        .count {
          margin: 0 5px;
        }
      </style>
    </head>
    
    <body>
    
      <div id="app"></div>
    
      <script src="../react/react.development.js"></script>
      <script src="../react/react-dom.development.js"></script>
      <script src="../react/babel.min.js"></script>
    
      <script src="./format-utils.js"></script>
    
      <script type="text/babel">
        // function formatPrice(price) {
        //   if (typeof price !== "number") {
        //     price = Number("aaa") || 0;
        //   }
    
        //   return "¥" + price.toFixed(2);
        // }
    
    
        class App extends React.Component {
          constructor(props) {
            super(props);
    
            this.state = {
              books: [
                {
                  id: 1,
                  name: '《算法导论》',
                  date: '2006-9',
                  price: 85.00,
                  count: 2
                },
                {
                  id: 2,
                  name: '《UNIX编程艺术》',
                  date: '2006-2',
                  price: 59.00,
                  count: 1
                },
                {
                  id: 3,
                  name: '《编程珠玑》',
                  date: '2008-10',
                  price: 39.00,
                  count: 1
                },
                {
                  id: 4,
                  name: '《代码大全》',
                  date: '2006-3',
                  price: 128.00,
                  count: 1
                },
              ]
            }
          }
    
          // jsx相关的代码写在render函数的上面
          renderBooks() {
            return (
              <div>
                <table>
                  <thead>
                    <tr>
                      <th></th>
                      <th>书籍名称</th>
                      <th>出版日期</th>
                      <th>价格</th>
                      <th>购买数量</th>
                      <th>操作</th>
                    </tr>
                  </thead>
                  <tbody>
                    {
                      this.state.books.map((item, index) => {
                        return (
                          <tr>
                            <td>{index + 1}</td>
                            <td>{item.name}</td>
                            <td>{item.date}</td>
                            <td>{formatPrice(item.price)}</td>
                            <td>
                              <button disabled={item.count <= 1} onClick={e => this.changeBookCount(index, -1)}>-</button>
                              <span className="count">{item.count}</span>
                              <button onClick={e => this.changeBookCount(index, 1)}>+</button>
                            </td>
                            <td><button onClick={e => this.removeBook(index)}>移除</button></td>
                          </tr>
                        )
                      })
                    }
                  </tbody>
                </table>
                <h2>总价格: {this.getTotalPrice()}</h2>
              </div>
            )
          }
    
          renderEmptyTip() {
            return <h2>购物车为空~</h2>
          }
    
          render() {
            return this.state.books.length ? this.renderBooks() : this.renderEmptyTip();
          }
    
          changeBookCount(index, count) {
            // 扩展运算符,相当于浅拷贝
            const newBooks = [...this.state.books];
            newBooks[index].count += count;
            this.setState({
              // newBooks不能写成newBooks[index].count += count
              books: newBooks
            })
          }
    
          removeBook(index) {
            // React中设计原则: state中的数据的不可变性;
            this.setState({
              books: this.state.books.filter((item, indey) => index != indey)
            })
          }
    
          getTotalPrice() {
            // 1.for循环的方式
            // let totalPrice = 0;
            // for (let item of this.state.books) {
            //   totalPrice += item.price * item.count;
            // }
            // return formatPrice(totalPrice);
    
            // 2.filter/map/reduce(归纳为)
            // 回调函数的参数:
            // 参数一: 上一次回调函数的结果(第一次没有上一次函数的回调函数的结果, 使用初始化值)
            const totalPrice = this.state.books.reduce((preValue, item) => {
              return preValue + item.count * item.price;
            }, 0);
    
            return formatPrice(totalPrice);
          }
        }
    
        ReactDOM.render(<App />, document.getElementById("app"));
      </script>
    
    </body>
    
    </html>
    
  • 相关阅读:
    简单批处理内部命令简介(转)
    CPU 内存 频率 DDR DDR2 DDR3
    python 正则表达式
    bat 脚本 > >> 管道
    python 多进程 无数进程 重复进程 死机
    NLP相关期刊和会议
    deamon tools dtsoft virtual cdrom device 失败 错误
    占位
    2011年07月03日的日记
    每周总结(第二周)
  • 原文地址:https://www.cnblogs.com/jianjie/p/14269555.html
Copyright © 2020-2023  润新知