图书管理
还记得搭建项目的时候在db.json文件里写的book吗?
来回顾一下book这个“数据表”的结构:
{
...
"book": [
{
"id": 10000,
"name": "前端从入门到精通",
"price": 9990,
"owner_id": 10000
},
{
"id": 10001,
"name": "Java从入门到放弃",
"price": 1990,
"owner_id": 10001
}
]
}
除了id外,每本书都包含name、price和owner_id三个字段。
有了之前实现用户管理的经验,我们很快就可以实现图书的增删改查,两者的代码基本相同,此处不再赘述(代码请查看项目代码的C09_book版本)。
关于【用户管理】与【图书管理】之间相同的代码,可以使用更高层次的高阶组件来实现组件的配置化(留个坑抽空填)。若你有更好的想法,欢迎在博客中留言与我进一步探讨。
图书的添加/编辑有一个owner_id用来代表图书的“所有者”,它的值是用户表中一个用户的id,一个用户能拥有多本书,一本书只能被一个用户拥有,这是一个一对多的关系。
上面提到的代码中只是简单地提供了一个输入框来接收输入的用户ID,这样的体验并不够好,我们来实现一个通用的自动完成组件。
自动完成组件
自动完成(英语:Auto-Complete)功能,指用户在输入一个字符串的部分内容时,就提供下拉菜单自动推荐相关常用字符串供用户选择以快速输入的一项功能特性。
找了个例子看一下效果:
可以发现,这是一个包含一个输入框、一个下拉框的复合控件。
实现一个通用组件,在动手写代码之前我会做以下准备工作:
- 确定组件结构
- 观察组件逻辑
- 确定组件内部状态(state)
- 确定组件向外暴露的属性(props)
组件结构
上面提了,这个组件由一个输入框和一个下拉框组成。
注意,这里的下拉框是一个“伪”下拉框,并不是指select与option。仔细看上面的动图,可以看得出来这个“伪”下拉框只是一个带边框的、位于输入框正下方的一个列表。
我们可以假设组件的结构是这样的:
<div>
<input type="text"/>
<ul>
<li>...</li>
...
</ul>
</div>
组件逻辑
观察动图,可以发现组件有以下行为:
- 未输入时,与普通输入框一致
- 输入改变时如果有建议的选项,则在下放显示出建议列表
- 建议列表可以使用键盘上下键进行选择,选择某一项时该项高亮显示,并且输入框的值变为该项的值
- 当移出列表(在第一项按上键或在最后一项按下键)时,输入框的值变为原来输入的值(图中的“as”)
- 按下回车键可以确定选择该项,列表消失
- 可以使用鼠标在列表中进行选择,鼠标移入的列表项高亮显示
组件内部状态
一个易用的通用组件应该对外隐藏只有内部使用的状态。使用React组件的state来维护组件的内部状态。
根据组件逻辑,我们可以确定自动完成组件需要这些内部状态:
- 逻辑2|3|4:输入框中显示的值,默认为空字符串(displayValue)
- 逻辑3|6:建议列表中高亮的项目,可以维护一个项目在列表中的索引,默认为-1(activeItemIndex)
组件暴露的属性
我们的目标是一个通用的组件,所以类似组件实际的值、推荐列表这样的状态,应该由组件的使用者来控制:
如上图,组件应向外暴露的属性有:
- value:代表实际的值(不同于上面的displayValue表示显示的、临时的值,value表示的是最终的值)
- options:代表当前组件的建议列表,为空数组时,建议列表隐藏
- onValueChange:用于在输入值或确定选择了某一项时通知使用者的回调方法,使用者可以在这个回调方法中对options、value进行更新
实现
确定了组件结构、组件逻辑、内部状态和外部属性之后,就可以着手进行编码了:
在/src/components
下新建AutoComplete.js文件,写入组件的基本代码:
import React from 'react';
class AutoComplete extends React.Component {
constructor (props) {
super(props);
this.state = {
displayValue: '',
activeItemIndex: -1
};
}
render () {
const {displayValue, activeItemIndex} = this.state;
const {value, options} = <