接下来我们实现一个前端页面,基本需求如下:
- 一个列表,包含所有商品的信息(名称,单位,单价,优惠信息),每个item可以加入购物车,并且可以选择加入购物车的商品数量。
- 一个购物车页面,从列表页面可以进入购物车页面,购物车页面列出所有你选择的商品。
- 确认购买后,将购物车内的信息传到后端。
今天先看第一个需求,商品列表。emmm...
我们可以把页面看成一个包含多个 Item
组件的 List
组件,至于Item
中调整数量的部分,我们已经有 Counter
了,所以,主要任务就是实现 Item
组件,以及 ItemList
组件。
组件结构
我们的页面大致是这样:
商品列表组件 ItemList
,其中包含多个 Item
组件,每个 Item
组件,用于显示单一商品信息,其中包含一个 Counter
组件。
先来写结构,大概还记得组件的嵌套吧?
新建 Item.js
:
import React,{Component} from 'react';
class Item extends Component{
render(){
return(
<div>
Item
<Counter />
</div>
)
}
}
export default Item
新建 ItemList.js
:
import React,{Component} from 'react';
class ItemList extends Component{
render(){
return(
<div>
ItemList
<Item />
</div>
)
}
}
export default ItemList
直接在 index.js
中将 ItemList
渲染到页面:
ReactDOM.render(<ItemList/>, document.getElementById('root'));
到此为止,ItemList
中包含了一个 Item
,这个 Item
中又包含了一个 Counter
:
列表
假设商品列表的数据,存放在 ItemList
中的一个数组当中:
const items = [
{barcode: 'ITEM000000', name: '可口可乐', unit: '瓶', price: 3.00},
{barcode: 'ITEM000001', name: '雪碧', unit: '瓶', price: 3.00},
{barcode: 'ITEM000002', name: '苹果', unit: '斤', price: 5.50},
{barcode: 'ITEM000003', name: '荔枝', unit: '斤', price: 15.00},
{barcode: 'ITEM000004', name: '电池', unit: '个', price: 2.00},
{barcode: 'ITEM000005', name: '方便面', unit: '袋', price: 4.50}
]
最直观的做法,构建6个 Item
组件,并分别将 name
,unit
,price
传入,Item
组件中接收传入的数据并显示。先来改写 Item 组件,通过 props
使用。
当然应该没有人会那么做吧……我们直接在 ItemList
中 构建列表,并给在构建每个子组件 Item 时通过属性设置 传入Item
对象,在 Item 组件中通过this.props.item.xxx
使用传入的 item
的数据,以此构建出 JSX
元素。
先在 Item
组件中接收数据,并为元素添加上样式。
...
render(){
return(
<div className="item">
<div className="item-info">
<span className="item-name">{this.props.item.name}</span>
<span className="item-price">
{this.props.item.price}元/{this.props.item.unit}
</span>
</div>
<Counter/>
</div>
)
}
...
给 Item
组件中加了默认值后的效果:
在
ItemList
组件中,你可以通过遍历,构建列表:
render(){
var itemList = []
for(let item of items){
itemList.push(<Item item={item}/>)
}
return(
{itemList}
)
}
当然,也可以使用 ES6 的 map
,看起来更加简洁:
render(){
return(
{items.map(item => (<Item item={item}/>)}
)
}
上面的代码中,我们使用操作符 =>
定义了一个临时函数,左边的括号中为输入的参数(单个 Item
对象),右边的花括号中是函数体,内容为对数据进行的操作以及返回值(对每个 Item
对象,返回一个 Item
组件实例)。
这两种创建列表方法的效果一致:
key
看起来还不错,但是,但是,但是,console
不高兴了。
unique "key",emmm.... 既然你要,那就给你好了。
<Item item={item} key={item.barcode}/>
好了没有 Warning 了,问题解决,大快人心。
但是,
不是你要我加我就加的,那我岂不是很没面子。
为什么需要这样一个属性呢?
可以说,这个 unique key 和数据库中的 primary key 差不多,都是为了对数据进行 唯一标识。我们在给列表中的 子组件 设置 key
值的时候,尽量保证其唯一性,当然直接使用数据的 后台ID 是最好不过了。
一个 key
对应一个组件,当组件需要移动和组件之间需要交换的时候,也就是涉及到数组 动态变化 的时候,可以方便 React.js
快速找出列表中需要重新渲染的组件,来 避免重新渲染整个列表,节省开销。如你所见,这个属性 key
是 React.js
作为内部数据使用的,我们虽然把 key
传给了子组件,但是在子组件的内部,是无法通过 props
访问的。
不过,在商品列表的例子中,Item
数组中的数据仅仅用于展示,没有涉及到数组的变更,使用遍历中的 index
作为 key
,也是没有问题的。
然后,我们再加上“优惠信息”,简单处理一下显示效果:
const promotions = [
{
type: 'BUY_TWO_GET_ONE_FREE',
barcodes: ['ITEM000000', 'ITEM000001', 'ITEM000005']
}
]
...
getCommodityPromotions(barcode){
let promotionsType = null;
promotions.map(promotion => {
if(promotion.barcodes.includes(barcode)){
promotionsType = promotion.type === "BUY_TWO_GET_ONE_FREE" ? "【买二赠一】" : promotion.type
}
})
return promotionsType
}
<Item ... promotion={this.getCommodityPromotions(item.barcode)}/>
...
在 Item
中通过 this.props.promotion
显示。再给 ItemList
加上标题,按钮,样式。丑是丑,但这个页面的基本元素已经完成的差不多了。
今天就到这里了。