通过 ToDo 的小项目实战,我们可以回顾页面布局,事件的监听,React Native 中的钩子函数使用。
首先我们先完成项目的整体框架搭建,把页面中相关的元素和样式类名定义好。并且表明对应单独组建的位置,具体的实例如下:
<View style={styles.container}>
{/* 后续补充头部组建 */}
<View style={styles.content}>
{/* 后续补充表单组建 */}
<View style={styles.list}>
<FlatList
data={todo}
renderItem={({ item }) => <Text>{item.title}</Text>}
/>
</View>
</View>
</View>
const styles = StyleSheet.create({
container: {
flex: 1,
},
content: {
padding: 40,
},
list: {
marginTop: 20,
},
});
任务列表的头部组建只是展示标题,所以在编写代码的时候比较简单
export default function header() {
return (
<View style={styles.header}>
<Text style={styles.title}>我的任务列表</Text>
</View>
);
}
const styles = StyleSheet.create({
header: {
height: 50,
backgroundColor: "coral",
justifyContent: "center",
},
title: {
textAlign: "center",
color: "#FFFFFF",
fontSize: 20,
fontWeight: "bold",
},
});
编写完成头部组建后,只要我们在最核心的组件中引入就可以。
在整体项目搭建的时候,我们是把任务编写在根级元素上,这样我们的代码可能在维护上会比较麻烦,所以我们需要把任务项作为一个子组件来维护。具体代码如下:
// 删除任务项
const pressHandler = (id: number) => {
setTodo((prevTodos: ToDoIem[]) => prevTodos.filter((item) => item.id !== id));
};
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
import React from "react";
interface ToDoIem {
title: string;
id: number;
}
export default function todoItem(props: {
item: ToDoIem;
pressHandler: Function;
}) {
return (
<TouchableOpacity onPress={() => props.pressHandler(props.item.id)}>
<Text style={styles.item}>{props.item.title}</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
item: {
padding: 16,
marginTop: 16,
borderColor: "#bbb",
borderWidth: 1,
borderStyle: "dashed",
borderRadius: 10,
},
});
最后一步就是实现任务的添加,具体的代码如下:
// 添加任务项
const submitHandler = (val: string) => {
// 判断任务标题的长度
if (val.length > 3) {
setTodo((prevTodos: ToDoIem[]) => {
return [{ title: val, id: prevTodos.length + 1 }, ...prevTodos];
});
} else {
Alert.alert("信息提示", "任务名称长度必须大于3个字符", [
{ text: "关闭", onPress: () => {} },
]);
}
};
export default function addToDo(props: { submitHandler: Function }) {
const [text, setText] = useState<string>("");
const changeHandler = (val: string) => {
setText(val);
};
return (
<View>
<TextInput
style={styles.input}
value={text}
placeholder="添加任务..."
onChangeText={(val) => changeHandler(val)}
/>
<Button
onPress={() => {
props.submitHandler(text);
setText("");
Keyboard.dismiss();
}}
title="添加任务"
color="coral"
/>
</View>
);
}
const styles = StyleSheet.create({
input: {
marginBottom: 10,
paddingHorizontal: 8,
paddingVertical: 6,
borderBottomWidth: 1,
borderBottomColor: "#DDDDDD",
},
});
现在我们的软件键盘是不会自己收起的,我们可以实现用户点击任何区域,软件键盘就会自动收起的效果,具体实例代码如下:
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss(); // 关闭键盘
}}
>
<View style={styles.container}>
<Header />
<View style={styles.content}>
<AddToDo submitHandler={submitHandler} />
<View style={styles.list}>
<FlatList
data={todo}
renderItem={({ item }) => (
<TodoItem item={item} pressHandler={pressHandler} />
)}
/>
</View>
</View>
</View>
</TouchableWithoutFeedback>
完整代码下载