我正在尝试使用react native实现搜索和过滤栏,但不太确定如何使用DataSource对象。数据采用JSON形式,它应该执行以下操作:
以下是RNPlay (Link)上的一个非常简单的示例。
如何在react native中实现搜索和过滤功能?
getAsString()
答案 0 :(得分:2)
这是解决方案,它在一个函数中进行搜索和过滤。欢迎提出如何改进的建议。
import React, {Component} from 'react';
import { AppRegistry, View, ListView, Text, TextInput, StyleSheet, TouchableOpacity } from 'react-native';
const FILTERS = [
{
tag: "clever", active: false
}, {
tag: "scary", active: false
}, {
tag: "friendly", active: false
}, {
tag: "obedient", active: false
}
];
const FIELDS = [
{
title:"Dog",
subtitle: "Bulldog",
tags: [ "clever", "scary" ],
active: true,
}, {
title:"Cat",
subtitle:"Persian cat",
tags: [ "friendly", "obedient" ],
active: true,
}, {
title:"Dog",
subtitle:"Poodle",
tags: [ "obedient" ],
active: true,
}
];
class SampleApp extends Component {
constructor(props) {
super(props);
var ds = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
});
var ds2 = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1.active !== row2.active,
});
this.state = {
dataSource: ds.cloneWithRows(FIELDS),
dataSource2: ds2.cloneWithRows(FILTERS),
filters: FILTERS,
};
}
renderFilter(filter) {
return (
<TouchableOpacity onPress={this.handleFilterClick.bind(this, filter)}>
<Text style={{fontSize: 24, backgroundColor:(filter.active)?'red':'grey', margin:5}}>{filter.tag}</Text>
</TouchableOpacity>
);
}
renderField(field) {
var fieldElement = <View style={{flexDirection:'column', borderWidth: 3, borderColor: 'yellow'}}>
<Text style={{fontSize: 24}}>{field.title}</Text>
<Text style={{fontSize: 24}}>{field.subtitle}</Text>
{field.tags.map((tagField) => {
return (
<View style={{backgroundColor:'blue'}}>
<Text style={{fontSize: 24}}>{tagField}</Text>
</View>
);
})}
</View>
if (field.active == true) {
return fieldElement;
} else {
return null;
}
}
handleFilterClick(filter) {
const newFilters = this.state.filters.map(f => {
let copyF = {...f};
if (copyF.tag === filter.tag) {
copyF.active = !filter.active;
}
return copyF;
});
this.setState({
dataSource2: this.state.dataSource2.cloneWithRows(newFilters),
filters: newFilters
});
this.searchAndFilter();
}
setSearchText(event) {
let searchText = event.nativeEvent.text;
this.setState({
searchText,
});
this.searchAndFilter();
}
searchAndFilter() {
//Get filtered tags
var filteredTags = [];
this.state.filters.forEach((filter) => {
if (filter.active) {
filteredTags.push(filter.tag);
}
});
const searchResults = FIELDS.map(f => {
let copyF = {...f};
//Filter
if (filteredTags.length !== intersect_safe(filteredTags, copyF.tags).length) {
copyF.active = false;
return copyF;
}
//Search
if (!this.state.searchText || this.state.searchText == '') {
copyF.active = true;
} else if (copyF.title.indexOf(this.state.searchText) != -1) {
copyF.active = true;
} else if (copyF.subtitle.indexOf(this.state.searchText) != -1) {
copyF.active = true;
} else {
copyF.active = false;
}
return copyF;
});
this.setState({
dataSource: this.state.dataSource.cloneWithRows(searchResults),
});
}
render() {
return (
<View>
<TextInput
style={styles.searchBar}
value={this.state.searchText}
onChange={this.setSearchText.bind(this)}
placeholder="Search" />
<ListView
style={{flexDirection:'row', flex:1, flexWrap:'wrap'}}
horizontal={true}
dataSource={this.state.dataSource2}
renderRow={this.renderFilter.bind(this)}
/>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderField.bind(this)}
/>
</View>
);
}
}
function intersect_safe(a, b)
{
var ai=0, bi=0;
var result = [];
while( ai < a.length && bi < b.length )
{
if (a[ai] < b[bi] ){ ai++; }
else if (a[ai] > b[bi] ){ bi++; }
else /* they're equal */
{
result.push(a[ai]);
ai++;
bi++;
}
}
return result;
}
const styles = StyleSheet.create({
searchBar: {
marginTop: 30,
fontSize: 40,
height: 50,
flex: .1,
borderWidth: 3,
borderColor: 'red',
},
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);