const OrderItem = (props) => { const [item,setItem] = useState(props.content) const [editing,setEditing] = useState(false) const [commentVal,setCommentVal] = useState(item.commentVal || '') const [star,setStar] = useState(item.star || 0) //评论框 const domCommentBox=() =>{ return ( <div className='orderItem__commentBox'> <textarea className='orderItem__edit' value={commentVal} onChange={commentChange}></textarea> {domCommentStar()} <button className='orderItem__btn orderItem__btn--save' onClick={commentSave}>提交</button> <button className='orderItem__btn orderItem__btn--cancel' onClick={commentCancel}>取消</button> </div> ) } //评星级 const domCommentStar=()=>{ return( <div className='orderItem-star'> { [1,2,3,4,5].map((i,index)=>{ const light = star >= i ? "orderItem-star--light" : "" return <span className={light} key={index} onClick={starClick.bind(this,i)}>★</span> }) } </div> ) } const starClick=(i)=>{ setStar(i) } const commentClick=()=>{ setEditing(true) } const commentChange=(e)=>{ setCommentVal(e.target.value) } const commentCancel=()=>{ setEditing(false) setCommentVal('') setStar(0) } //提交评价 const commentSave=()=>{ // fetch('/commentSave').then(res=>{ // if(res.ok){ //请求成功后模拟渲染页面 const newItem = {...item,commentVal,star,ifEvaluate:true} setItem(newItem) console.log(newItem) setEditing(false) // } // }) } return ( <div className='orderItem'> <div className='orderItem-main'> <div className='orderItem__imgBox'> <img className='orderItem__img' src={item.img}/> </div> <div className='orderItem__cont'> <div className='orderItem__title'>{item.title}</div> <div className='orderItem__detail'>{item.detail}</div> <div className='orderItem__price'>{item.price}</div> </div> <div className='orderItem__btnBox'> { item.ifEvaluate ? (<button className='orderItem__btn orderItem__btn--true'>已评价</button>) : (<button className='orderItem__btn orderItem__btn--false' onClick={commentClick}>评价</button>) } </div> </div> {editing ? domCommentBox() : null} </div> ); };
const OrderItem = (props) => { //订单子组件 const item = props.content //传递过来的数据 return ( <div className='orderItem'> <div className='orderItem__imgBox'> <img className='orderItem__img' src={item.img}/> </div> <div className='orderItem__cont'> <div className='orderItem__title'>{item.title}</div> <div className='orderItem__detail'>{item.detail}</div> <div className='orderItem__price'>{item.price}</div> </div> <div className='orderItem__btnBox'> { //按钮状态 item.ifEvaluate ? (<button className='orderItem__btn--true'>已评价</button>) : (<button className='orderItem__btn--false'>评价</button>) } </div> </div> ); };
const OrderList = () => { //订单列表组件 const [list,setList] = useState([]) useEffect(()=>{ //DOM更新之后调用 fetch('/mock/orders.json').then(res=>{ //请求数据 if(res.ok){ res.json().then(data=>{ setList(data) }) } }) }) return ( <div> { list.map((item,index)=>{ //列表遍历 return <OrderItem key={index} content={item}/> }) } </div> ); };
使用 create-react-app 快速搭建项目
根据UI划分页面组件,头部、订单列表、订单详情
组件的详细开发
通过mock获取服务器数据
将数据放到public/mock文件夹,调用路径写 /mock/orders.json'
使用fetch() 获取ajax数据
坑:setState() 是方法,不是赋值
组件挂载完后请求数据
| componentDidMount
componentDidMount(){ fetch('/mock/orders.json').then(res => { if(res.ok){ res.json().then(data => { this.setState({ data }) }) } }) }
获取列表数据,保持到data变量中
通过 data.map() 遍历列表数据
演示数据
const data = [ { "id": 1, "shop": "院落创意菜", "picture": "http://www.qwphp.com/web/uploads/2016-03-07/159cbcca4f2f5959e9ba209eecbf0d5a.jpg", "product": "百香果(冷饮)1扎", "price": 19.9, "ifCommented": false }, { "id": 2, "shop": "正一味", "picture": "http://www.qwphp.com/web/uploads/2016-03-07/a7368d9b6bee0d505a220cd903dcd43c.jpg", "product": "肥牛石锅拌饭+鸡蛋羹一份", "price": 25, "ifCommented": false }, { "id": 3, "shop": "冻酸奶", "picture": "http://www.qwphp.com/web/uploads/2016-03-07/4c21dde63b15de6bed3a02305a9ab8c3.jpg", "product": "冻酸奶(小杯)一杯", "price": 8, "ifCommented": true }, { "id": 4, "shop": "吉野家", "picture": "http://www.qwphp.com/web/uploads/2016-03-07/0444fdd46ef30cb81b706ef27f18295f.jpg", "product": "鸡汁烧鱼+中杯汽水/紫菜蛋花汤", "price": 20, "ifCommented": true } ]
BEM 命名规范
| Bem 是块(block)、元素(element)、修饰符(modifier)的简写,由 Yandex 团队提出的一种前端 CSS 命名方法论。
__双下划线:代表层级关系
-- 双中杆: 代表不同状态
按钮状态可以用 三目运算符 ? :
划分依据
根据视图层的UI划分
订单列表也可以拆分为 header, orderList, OrderItem 三个组件
拆分方式
每个组件用单独的文件夹包裹
文件夹中放 index.js 和 style.css
使用react snippet 插件 rrc 快速创建组件模板
组件的文件结构
components
Header
index.js
style.css
OrderList
index.js
style.css
OrderItem
index.js
style.css
将App.js 转到 components文件夹统一管理
components\App
index.js → 由App.js重命名
style.css → 有App.css重命名
安装项目
npx create-react-app my-order
npm 镜像源切换
| npm set registry http://registry.npmmirror.com
package.json
dependencies 安装好的依赖
react-scripts 封装 webpack相关的工作,支持热更新
课程目标
掌握React项目的开发流程
理解和应用React组件化思想
案例效果
手机端订单列表
使用Chrome的手机模式调试
Vscode插件
npm Intellisense
| 自动补全依赖模块的提示
Path Intellisense
| 路径补全提示
Prettier-Code formatter
| 代码格式化
Reactjs code snippets
| react 代码模板
React 简介
构建用户界面的JS库
声明式的视图层
以组件为基础
知识回顾
JSX
支持HTML标签和自定义组件
支持JS变量和表达式
Props和State
Props组件对外接口
通过属性和方法进行父子组件通信
State组件对内接口
内部数据状态
|
组件声明周期(钩子函数)
挂载
constructor()
componentDidMount()
更新
componentDidUpdate()
卸载
componentWillUnmount()
列表和Keys
唯一的key属性
事件处理
事件名用小驼峰
事件指向 需要 bind 指向组件实例
箭头函数不需要处理this问题
表单
受控组件 → 数据由react的state管理
数据统一管理,可以减少bug
react: 构建用户界面的JavaScript库,声明式的视图层,以组件为基础
基础知识
*JSX
*Props和State
*组件生命周期
*列表和keys
当列表数据发生变化时,react将key作为每一个列表项的唯一标识,去判断列表的变化,减少不必要的重复渲染
*事件处理
驼峰写法
this绑定或用箭头函数
*表单
受控组件 通过state管理
handleChange(event){ this.setState({value: event.target.value}); }
<input type="text" value={this.state.value} onChange={this.handleChange} />
不受控组件
如果props.data.stars是有值的就取该值,否取值为0
id值相同用===,如果相同,将item中的comment、stars、ifCommented(值为true)修改掉,如果不同,仍然返回item
在挂载函数compoentDidMount中获取后台数据,使用html5的fetch函数请求数据。
在构造函数中定义一个初始的state值。
在React中写js需要用到{}
从props中获取data,从data中拿到shop、product、price、picture字段
React的基本框架
input的值一旦被改变,会触发onChange方法,onChange方法中的setState方法给value赋值,组件会重新渲染,render会被重新执行,value就会被设置成state中的value的值。
若没有bind的语句的话,handleClick事件中的this指的是button的点击事件对象
也可以通过es6的箭头函数来表示该this是当前组件
不再React中和在React中写事件:
组件的挂载状态的方法:
constructor()
render()
componentDidMount()
组件更新状态的方法有:
render()
componentDidUpdate()
组件的卸载状态的方法有:
componentWillUnmount()
/*我的css简洁一些,效果一样*/
.orderItem{width: 100%;height: 30vw;margin: 5px auto;}
.orderItem__pic{width: 100%;height: 100%;}
.orderItem__picContainer{width: 30vw;height: 30vw;float: left;}
.orderItem__content{width: 63vw;/*background: lightblue;*/margin-top:10px;display: inline-block;float: right;}
.orderItem__product{font-weight: 700;font-size: 17px;line-height: 30px;}
.orderItem__shop{color: #777;line-height: 30px;text-overflow: ellipsis;white-space: nowrap;}
.orderItem__price{color: #777;float: left;line-height: 30px;}
.orderItem__price::before{content: '¥';}
.orderItem__btn{color: white;background: lightgray;float: right;width: 80px;height: 22px;border: 0;}
.orderItem__btn--red{background-color: #e9203d}
.orderItem__btn--grey{background-color: #999}
安装插件
npm intellisense
Path intellisense
Prettier-code formatter
Reactjs code snippets
map ...
onClick={this.handleClickStars.bind(this, item)}
给当前点击事件传值(当前项)
Props 和 State 的区别
二者都是数据传递的形式
前者对外父子组件之间通信
后者对内负责数据的修改