视频地址
React 16 实现订单列表及评价功能
简介:React 以其组件化的思想在前端领域大放异彩,但其革命化的前端开发理念对很多 React 初学者来说, 却很难真正理解和应用到真实项目中。本课程面向掌握了 React 基础知识但缺乏实战经验的开发者, 选取典型实战案例,基于 React 16 开发,介绍了从项目创建、到组件划分、再到组件及页面逻辑实现的开发流程,帮助缺乏实战经验的人掌握 React 开发的基本思想和理念。
课程大纲
- 课程综述
- React基础知识回顾
- 订单列表及评价案例实现
- 课程总结
面向用户
- 具备 React基础
- 缺少项目实战经验
- 初、中级前端开发者或前端爱好者
课程目标
- 掌握 React项目的开发流程
- 理解和应用 React 组件化的思想
开发环境
- React 16.4.2
- Nodejs (v8.2.1)
- NPM (v6.3.0)
- Visual Studio Code
React 简介
- 构建用户界面的 JavaScript 库
- 声明式的视图层
- 以组件为基础
React 基础知识回顾
- JSX
- Props和- State
- 组件生命周期
- 列表和 Keys
- 事件处理 onClick={}
- 表单 Forms
使用 create-react-app 创建项目结构
实战案例
- 项目结构创建
- 页面组件划分
- 页面组件实现
- 获取服务器数据
项目结构创建
创建-响应-应用程序(npm5.2 以上)
create-react-app(npm 5.2+)
npx create-react-app my-order
课程须知
- 了解基本的 React知识
老师告诉你能学到什么?
- create-react-app脚手架的使用Create React App 中文文档
- React项目开发流程
- 组件划分方法
- 组件间的通讯
- 列表渲染
- 组件事件处理
- React 项目中的数据请求
第 1 章 课程介绍
课程介绍,案列效果演示,开发环境准备。
React 基本概念和主要特点介绍:
- JSX
- props和- state
- 生命周期
- 事件绑定
- 列表渲染
第 2 章 实战案例讲解
介绍
- 如何使用脚手架创建 React 项目
- React 项目中页面组件的划分方法
- 组件间的通讯
- 组件列表的渲染
- 使用 fetch获取接口数据
- 以及组件的事件绑定。
第 3 章 课程总结
- 回顾案例和涉及的 React 知识点。
个人实战截图

项目目录

publick/mock/json
[
  {
    "id": 1,
    "shop": "创意园区",
    "picture": "https://inews.gtimg.com/newsapp_bt/0/12886421894/641",
    "product": "百香果(冷饮)1扎",
    "price": 19.9,
    "isCommented": false
  },
  {
    "id": 2,
    "shop": "老默之家",
    "picture": "https://n.sinaimg.cn/sinacn07/224/w640h384/20181126/c2d3-hpevhck6865027.jpg",
    "product": "想吃鱼了",
    "price": 39.9,
    "isCommented": true
  },
  {
    "id": 3,
    "shop": "大吉大利店",
    "picture": "https://img1.baidu.com/it/u=4204641963,3545807278&fm=253&fmt=auto&app=138&f=JPEG?w=537&h=500",
    "product": "今晚吃鸡",
    "price": 49.9,
    "isCommented": false
  }
]
compoents/APP/index.js
import React, { Component } from 'react';
import OrderList from '../OrderList';
import Header from '../Header'
import './style.css';
function App() {
  return (
    <div className="App">
      <Header></Header>
      <OrderList />
    </div>
  );
}
export default App;
compoents/APP/style.css
* {
  margin: 0;
  padding: 0
}
compoents/Header/index.js
import React, { Component } from 'react';
import './style.css'
class Header extends Component {
  render() {
    return (
      <div>
         <div className='my_order_title'>我的订单</div>
      </div>
    );
  }
}
export default Header;
compoents/Header/style.css
.my_order_title {
  background:rgb(229,29,52);
  color: white;
  text-align: center;
  padding: 10px 0;
}
compoents/OrderItem/index.js
import React, { Component } from 'react';
// import logo from '../../logo.svg'
// import goodImg from '../../assets/images/good.jpg'
import './style.css'
class OrderItem extends Component {
  constructor(props) {
    super(props);
    this.state = {
      editing: props.data.editing || false,
      stars: props.data.stars || 0,
      comment: props.data.comment || ''
    }
  }
  render() {
    const { picture, product, shop, price, isCommented } = this.props.data
    return (
      <div>
        <div className='order_item'>
            <div className='info_item'>
              <img className='img' src={picture} alt='' />
              <div>
                <div className="good_product">{product}</div>
                <div className="good_shop">{shop}</div>
                <div className="good_price">¥{price}</div>
              </div>
            </div>
            <div>
              {
                isCommented 
                ? <div className="un_comment_box" onClick={this.handleOpenEditArea}>评价</div>
                : <div className="had_comment_box">已评价</div>
              }
            </div>
            {/* <div className={isCommented ? 'un_comment_box' : 'had_comment_box'}>{isCommented? '评价': '已评价'}</div> */}
          </div>
        <div>{this.state.editing ? this.renderEditArea() : null}</div>
      </div>
    );
  }
  renderEditArea() {
    return (
      <div className='order_comment_box'>
        <textarea 
          onChange={this.handleCommentChange}
          value={this.state.comment}
          rows={4} 
          className='order_comment_text' />
        {this.renderStars()}
        <div className='btn_box'>
          <div className='order_submit' onClick={this.handleSumbitComment}>提交</div>
          <div className='order_cancel' onClick={this.handleCancelComment}>取消</div>
        </div>
      </div>
    )
  }
  renderStars() {
    const { stars } = this.state;
    return (
      <div>
        {
          [1, 2, 3, 4, 5].map((item,index) => {
            const lightClass = stars >= item ? 'orderItem__star--light' : ''
            return (
              <span className={"orderItem__star " + lightClass} key={index} onClick={this.handleClickStars.bind(this, item)}>★</span>
            )
          })
        }
        
      </div>
    )
  }
  handleOpenEditArea = () => {
    console.log('this.props.data.editing',this.props.data.editing)
    this.setState({
      // editing: !this.props.data.editing
      editing: !this.state.editing
    })
  }
  handleCommentChange = (e) => {
    this.setState({
      comment: e.target.value
    })
  }
  handleClickStars = (stars) => {
    this.setState({
      stars : stars
    })
  }
  handleCancelComment = () => {
    this.setState({
      editing : false,
      stars: this.props.data.stars || 0,
      comment: this.props.data.comment || ''
    })
  }
  handleSumbitComment = () => {
    const { id } = this.props.data;
    const { comment, stars } = this.state
    this.setState({
      editing : false,
    })
    this.props.onSubmit(id, comment, stars)
  }
}
export default OrderItem;
compoents/OrderItem/style.css
.order_item {
  display: flex;
  padding: 12px;
  justify-content: space-between;
  align-items: flex-end;
}
.info_item {
  display: flex;
}
.img_item {
  width: 65px;
  height: 65px;
}
.img {
  width: 65px;
  height: 65px;
  margin-right: 12px;
}
.good_product {
  font-weight: 700;
  margin-bottom: 8px;
}
.good_shop {
  color: #666;
  font-size: 10px;
  margin-bottom: 8px;
}
.good_price {
  color: red;
  font-weight: 700;
}
/* 未评价 */
.un_comment_box {
  padding: 4px 8px;
  color: white;
  background: red;
  border-radius: 6px;
}
/* 已评价 */
.had_comment_box {
  padding: 4px 8px;
  color: white;
  background: #888;
  border-radius: 6px;
}
.order_comment_box {
  width: 100%;
  background: antiquewhite;
  padding: 10px;
}
.order_comment_text {
  width: 90%;
  border: #999;
}
.star_box {
  font-size: 18px;
}
.btn_box {
  display: flex;
}
.order_submit {
  padding: 4px 18px;
  color: white;
  background: red;
  border-radius: 6px;
  margin-right: 10px;
}
.order_cancel {
  padding: 4px 18px;
  color: white;
  background: #888;
  border-radius: 6px;
}
.light {
  background: crimson;
}
.orderItem__star{
  color: gray;
  font-size: 25px;
}
.orderItem__star--light{
  color: gold;
  font-size: 25px;
}
compoents/OrderList/index.js
import React, { Component } from 'react';
import OrderItem from '../OrderItem';
import './style.css'
class OrderList extends Component {
  constructor(props) {
    super(props)
    this.state = { data: [] }
  }
  componentDidMount() {
    fetch('/mock/orders.json').then(res => {
      if(res.ok) {
        res.json().then(data => {
          this.setState({
            data
          })
        })
      }
    })
  }
  render() {
    return (
      <div>
        {
          this.state.data.map(item=>{
            return <OrderItem key={item.id} data={item} onSubmit={this.handleSubmit} />
          })
        }
        
      </div>
    );
  }
  handleSubmit = (id, comment, stars) => {
    const newData = this.state.data.map(item => {
      return item.id === id ? 
      {
        ...item, comment, stars, isCommented: true
      }
      : item
    })
    this.setState({
      data: newData
    })
  }
}
export default OrderList;
项目小结
- 主要跟着写核心的逻辑代码
- 样式和数据可以自己造
- 总体上难度不大~



















