在本节中,我们将实现类别模块的添加和删除功能。以下是详细的实现步骤:
一、更新 Item 组件
1. 添加编辑状态图标
在 pages/Category/Item.tsx 中,根据编辑状态显示加号或减号图标:
import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import { ICategory } from '@/models/category';
import { viewportWidth } from '@/utils/index';
export const parentWidth = viewportWidth - 10;
export const itemWidth = parentWidth / 4;
export const itemHeight = 48;
export const margin = 5;
interface IProps {
data: ICategory;
isEdit: boolean;
selected: boolean;
onPress: () => void;
onLongPress: () => void;
}
class Item extends React.Component<IProps> {
render() {
const { data, isEdit, selected, onPress, onLongPress } = this.props;
return (
<TouchableOpacity
activeOpacity={0.8}
onPress={onPress}
onLongPress={onLongPress}
style={styles.itemWrapper}
>
<View style={styles.item}>
<Text style={styles.text}>{data.name}</Text>
{isEdit && (
<View style={styles.icon}>
<Text style={styles.iconText}>{selected ? '-' : '+'}</Text>
</View>
)}
</View>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
itemWrapper: {
width: itemWidth,
height: itemHeight,
},
item: {
flex: 1,
margin: margin,
backgroundColor: '#fff',
borderRadius: 3,
justifyContent: 'center',
alignItems: 'center',
position: 'relative',
},
text: {
fontSize: 12,
},
icon: {
position: 'absolute',
top: -5,
right: -5,
height: 16,
width: 16,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f86442',
borderRadius: 8,
},
iconText: {
lineHeight: 15,
color: '#fff',
fontSize: 12,
},
});
export default Item;
二、更新分类页面
1. 处理类别点击和长按事件
在 pages/Category/index.tsx 中,处理类别点击和长按事件:
import React, { Component } from 'react';
import { View, Text, StyleSheet, ScrollView, Platform } from 'react-native';
import _ from 'lodash';
import Item from './Item';
import Touchable from '@/components/Touchable';
import moment from 'moment';
import { connect, ConnectedProps } from 'react-redux';
import { RootState } from '@/models/index';
import { ICategory } from '@/models/category';
import { RootStackNavigation } from '@/navigator/index';
import { editMode } from '@/utils/editMode';
import { fixedItems } from '@/constants';
import HeaderRightBtn from './HeaderRightBtn';
const marginHorizontal = 5;
const itemWidth = (viewportWidth - marginHorizontal * 2) / 4;
const mapStateToProps = ({ category }: RootState) => ({
categorys: category.categorys,
myCategorys: category.myCategorys,
isEdit: category.isEdit,
});
const connector = connect(mapStateToProps);
type ModelState = ConnectedProps<typeof connector>;
interface IProps extends ModelState {
navigation: RootStackNavigation;
}
interface IState {
myCategorys: ICategory[];
}
class Category extends Component<IProps, IState> {
state = {
myCategorys: this.props.myCategorys,
};
componentDidMount() {
const { categorys } = this.props;
const classifyGroup = _.groupBy(categorys, 'classify');
this.classifyGroup = classifyGroup;
}
onPress = (item: ICategory, selected: boolean) => {
const { isEdit } = this.props;
const { myCategorys } = this.state;
if (isEdit) {
if (selected) {
this.setState({
myCategorys: myCategorys.filter(
(selectedItem) => selectedItem.id !== item.id,
),
});
} else {
this.setState({
myCategorys: myCategorys.concat(item),
});
}
}
};
onLongPress = (index: number) => {
const { isEdit, dispatch } = this.props;
if (!isEdit) {
dispatch({
type: 'category/toggle',
});
}
};
render() {
const { isEdit, categorys } = this.props;
const { myCategorys } = this.state;
return (
<ScrollView style={styles.container}>
<View>
<Text style={styles.classifyName}>
我的分类<Text style={styles.tips}>长按可拖动顺序</Text>
</Text>
<View style={styles.classifyView}>
{myCategorys.map((item, index) => (
<Item
key={item.id}
data={item}
isEdit={isEdit}
selected
onPress={() => this.onPress(item, true)}
onLongPress={() => this.onLongPress(index)}
/>
))}
</View>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f3f6f6',
},
classifyName: {
fontSize: 16,
marginBottom: 8,
marginTop: 14,
marginLeft: 10,
},
tips: {
color: '#666',
},
classifyView: {
flexDirection: 'row',
flexWrap: 'wrap',
padding: 5,
},
});
export default connector(Category);
2. 保存数据到本地存储
在 models/category.ts 中,更新 toggle 方法,保存数据到本地存储:
*toggle(_, { put, select }) {
const category: CategoryModelState = yield select((state: RootState) => state.category);
yield put({
type: 'setState',
payload: {
isEdit: !category.isEdit,
},
});
if (category.isEdit) {
storage.save({
key: 'myCategorys',
data: category.myCategorys,
});
}
},
三、适配设备平台
在 navigator/index.tsx 中适配设备平台:
<Stack.Navigator
headerMode="float"
screenOptions={{
headerTintColor: '#333',
headerBackTitleVisible: false,
...Platform.select({
android: {
headerStatusBarHeight: StatusBar.currentHeight,
},
}),
}}
/>
四、总结
在本节中,我们实现了类别模块的添加和删除功能。通过动态显示加号和减号图标,用户可以方便地添加或删除类别。同时,我们还处理了长按事件切换编辑状态,并保存了数据到本地存储中。下一节,我们将学习如何实现类别的拖拽功能。