本文概述
作为每个用户, 我通常都很懒惰, 并且不想在输入中键入所有内容来搜索内容, 至少知道我们何时可以利用该技术使我们的生活更轻松。这就是存在自动完成字段的原因, 这个想法很简单, 你可以键入一些可能与列出的选项匹配的文本, 然后可以选择它, 因此你不会键入错误的信息, 因为可以从服务器或本地检索所有内容。
在本文中, 我们将向你展示如何轻松地在项目中实现自动完成组件, 以简化用户的生活。
要求
为了尽可能快和容易地实现自动完成组件, 我们建议你使用react-autocomplete模块。该模块提供了符合WAI-ARIA的React自动完成(组合框)组件, 可以根据你的需求轻松进行自定义。要使用它, 请在终端中使用NPM使用以下命令在模块中继续安装模块:
npm install --save react-autocomplete
安装后, 你将能够从” react-autocomplete”将组件作为”自动完成”导入。有关此库的更多信息, 请访问Github上的官方存储库。
A.创建同步自动完成
如果你愿意使用建议本地数据的自动完成字段(类中已有的对象数组), 则只需在类状态内定义数据并将其加载到自动完成组件的项目属性中即可。数据将采用仅由对象遵循的数组格式。每个对象都是自动完成列表的一项, 可以根据需要命名值(因为你可以定义对象的哪些属性在自动完成中呈现)。以下示例实现了组件的6个基本属性, 当输入更改或用户选择自动完成功能的某些选项时, 我们为基本操作定义了一个回调。
此外, 我们使用renderItem回调自定义每个渲染项目的结构, 并声明一个初始值, 在这种情况下, 使用声明状态的value属性将其为空:
import React from 'react';
// Import the Autocomplete Component
import Autocomplete from 'react-autocomplete';
export default class App extends React.Component {
constructor(props, context) {
super(props, context);
// Set initial State
this.state = {
// Current value of the select field
value: "", // Data that will be rendered in the autocomplete
autocompleteData: [
{
label: 'Apple', value: 1
}, {
label: 'Microsoft', value: 2
}, {
label: 'Me, Myself and I', value: 3
}
]
};
// Bind `this` context to functions of the class
this.onChange = this.onChange.bind(this);
this.onSelect = this.onSelect.bind(this);
this.getItemValue = this.getItemValue.bind(this);
this.renderItem = this.renderItem.bind(this);
}
/**
* Callback triggered when the user types in the autocomplete field
*
* @param {Event} e JavaScript Event
* @return {Event} Event of JavaScript can be used as usual.
*/
onChange(e){
this.setState({
value: e.target.value
});
console.log("The Input Text has changed to ", e.target.value);
}
/**
* Callback triggered when the autocomplete input changes.
*
* @param {Object} val Value returned by the getItemValue function.
* @return {Nothing} No value is returned
*/
onSelect(val){
this.setState({
value: val
});
console.log("Option from 'database' selected : ", val);
}
/**
* Define the markup of every rendered item of the autocomplete.
*
* @param {Object} item Single object from the data that can be shown inside the autocomplete
* @param {Boolean} isHighlighted declares wheter the item has been highlighted or not.
* @return {Markup} Component
*/
renderItem(item, isHighlighted){
return (
<div style={{ background: isHighlighted ? 'lightgray' : 'white' }}>
{item.label}
</div>
);
}
/**
* Define which property of the autocomplete source will be show to the user.
*
* @param {Object} item Single object from the data that can be shown inside the autocomplete
* @return {String} val
*/
getItemValue(item){
// You can obviously only return the Label or the component you need to show
// In this case we are going to show the value and the label that shows in the input
// something like "1 - Microsoft"
return `${item.value} - ${item.label}`;
}
render() {
return (
<div>
<Autocomplete
getItemValue={this.getItemValue}
items={this.state.autocompleteData}
renderItem={this.renderItem}
value={this.state.value}
onChange={this.onChange}
onSelect={this.onSelect}
/>
</div>
);
}
}
上一类将呈现一个非常简单的自动完成功能, 如下所示:
B.创建异步自动完成
通常, 自动完成功能也实现异步接口, 这意味着当用户键入输入时, 某些逻辑在后台运行并从服务器检索一些信息。得益于React方法和组件, 这并不是很难实现的, 因为我们使用React的状态为我们完成了艰苦的工作。
实现自动完成的过程将与同步过程相同, 但是只有一件事会改变, 即数据源。最初, 我们应该将autocompleteData设置为一个空数组, 因为我们应该从服务器中加载此信息。将远程数据加载到自动完成中的逻辑很简单, 我们只需要使用远程数据来更新autocompleteData的状态即可!显然, 数据的结构需要与本地逻辑中声明的匹配(以获取标签和值等)。在下面的示例中, 从远程源检索数据的函数是retrieveDataAsynchronously, 此函数在需要明确声明的onChange回调内部触发。该函数接收输入的当前文本作为第一个参数, 你的服务器端逻辑将使用该文本根据用户的请求发送一些数据:
import React from 'react';
// Import the Autocomplete Component
import Autocomplete from 'react-autocomplete';
export default class App extends React.Component {
constructor(props, context) {
super(props, context);
// Set initial State
this.state = {
// Current value of the select field
value: "", // Data that will be rendered in the autocomplete
// As it is asynchronous, it is initially empty
autocompleteData: []
};
// Bind `this` context to functions of the class
this.onChange = this.onChange.bind(this);
this.onSelect = this.onSelect.bind(this);
this.getItemValue = this.getItemValue.bind(this);
this.renderItem = this.renderItem.bind(this);
this.retrieveDataAsynchronously = this.retrieveDataAsynchronously.bind(this);
}
/**
* Updates the state of the autocomplete data with the remote data obtained via AJAX.
*
* @param {String} searchText content of the input that will filter the autocomplete data.
* @return {Nothing} The state is updated but no value is returned
*/
retrieveDataAsynchronously(searchText){
let _this = this;
// Url of your website that process the data and returns a
let url = `mywebsite/searchApi?query=${searchText}`;
// Configure a basic AJAX request to your server side API
// that returns the data according to the sent text
let xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = () => {
let status = xhr.status;
if (status == 200) {
// In this example we expects from the server data with the structure of:
// [
// {
// label: "Some Text", // value: 1, // }, // {
// label: "Some Other Text", // value: 1, // }, // ]
// But you can obviously change the render data :)
// Update the state with the remote data and that's it !
_this.setState({
autocompleteData: xhr.response
});
// Show response of your server in the console
console.log(xhr.response);
} else {
console.error("Cannot load data from remote source");
}
};
xhr.send();
}
/**
* Callback triggered when the user types in the autocomplete field
*
* @param {Event} e JavaScript Event
* @return {Event} Event of JavaScript can be used as usual.
*/
onChange(e){
this.setState({
value: e.target.value
});
/**
* Handle the remote request with the current text !
*/
this.retrieveDataAsynchronously(e.target.value);
console.log("The Input Text has changed to ", e.target.value);
}
/**
* Callback triggered when the autocomplete input changes.
*
* @param {Object} val Value returned by the getItemValue function.
* @return {Nothing} No value is returned
*/
onSelect(val){
this.setState({
value: val
});
console.log("Option from 'database' selected : ", val);
}
/**
* Define the markup of every rendered item of the autocomplete.
*
* @param {Object} item Single object from the data that can be shown inside the autocomplete
* @param {Boolean} isHighlighted declares wheter the item has been highlighted or not.
* @return {Markup} Component
*/
renderItem(item, isHighlighted){
return (
<div style={{ background: isHighlighted ? 'lightgray' : 'white' }}>
{item.label}
</div>
);
}
/**
* Define which property of the autocomplete source will be show to the user.
*
* @param {Object} item Single object from the data that can be shown inside the autocomplete
* @return {String} val
*/
getItemValue(item){
// You can obviously only return the Label or the component you need to show
// In this case we are going to show the value and the label that shows in the input
// something like "1 - Microsoft"
return `${item.value} - ${item.label}`;
}
render() {
return (
<div>
<Autocomplete
getItemValue={this.getItemValue}
items={this.state.autocompleteData}
renderItem={this.renderItem}
value={this.state.value}
onChange={this.onChange}
onSelect={this.onSelect}
/>
</div>
);
}
}
当用户键入自动完成功能时, 给定的文本将通过AJAX请求发送到服务器, 并且应作为响应返回一个数组, 该数组包含一些与用户提供的文本相匹配的数据。使用从服务器发送的数据更新状态, 用户可以选择一个选项。请注意, 此处的实现创建了一个ajax请求, 每次用户按下一个键时都会执行该请求, 这意味着很多请求, 因此你可能希望以某种方式对功能进行反跳处理。请记住, 你可以通过修改menuStyle属性仅使用CSS来自定义输入和自动完成项。
编码愉快!
评论前必须登录!
注册