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 的区别
二者都是数据传递的形式
前者对外父子组件之间通信
后者对内负责数据的修改