Appearance
个人主页/小工具APP - 表单提交
表单提交功能实现
在本节中,我们将为个人主页/小工具APP添加表单提交功能。我们将创建一个用户个人资料编辑页面,允许用户修改个人信息并提交表单。
步骤1:创建个人资料编辑页面
创建 src/screens/ProfileEditScreen.js 文件:
javascript
import React, { useState, useEffect } from 'react';
import { View, Text, TextInput, TouchableOpacity, StyleSheet, ScrollView, Alert } from 'react-native';
import { useNavigation, useRoute } from '@react-navigation/native';
const ProfileEditScreen = () => {
const navigation = useNavigation();
const route = useRoute();
// 从路由参数中获取当前用户信息
const initialData = route.params?.userData || {
name: '张三',
email: 'zhangsan@example.com',
phone: '13800138000',
bio: '这是个人简介',
};
// 表单状态
const [formData, setFormData] = useState(initialData);
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
// 处理输入变化
const handleChange = (name, value) => {
setFormData(prev => ({
...prev,
[name]: value
}));
// 清除错误
if (errors[name]) {
setErrors(prev => {
const newErrors = { ...prev };
delete newErrors[name];
return newErrors;
});
}
};
// 表单验证
const validateForm = () => {
const newErrors = {};
if (!formData.name.trim()) {
newErrors.name = '请输入姓名';
}
if (!formData.email.trim()) {
newErrors.email = '请输入邮箱';
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
newErrors.email = '请输入有效的邮箱地址';
}
if (!formData.phone.trim()) {
newErrors.phone = '请输入手机号';
} else if (!/^1[3-9]\d{9}$/.test(formData.phone)) {
newErrors.phone = '请输入有效的手机号';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
// 处理表单提交
const handleSubmit = async () => {
if (!validateForm()) {
return;
}
setIsSubmitting(true);
try {
// 模拟API请求
await new Promise(resolve => setTimeout(resolve, 1000));
// 提交成功
Alert.alert('成功', '个人信息已更新', [
{
text: '确定',
onPress: () => {
// 返回上一页并传递更新后的数据
navigation.goBack();
}
}
]);
} catch (error) {
Alert.alert('错误', '提交失败,请稍后重试');
} finally {
setIsSubmitting(false);
}
};
return (
<ScrollView style={styles.container}>
<View style={styles.form}>
<Text style={styles.title}>编辑个人资料</Text>
<View style={styles.inputContainer}>
<Text style={styles.label}>姓名</Text>
<TextInput
style={[styles.input, errors.name && styles.inputError]}
value={formData.name}
onChangeText={(text) => handleChange('name', text)}
placeholder="请输入姓名"
/>
{errors.name && <Text style={styles.errorText}>{errors.name}</Text>}
</View>
<View style={styles.inputContainer}>
<Text style={styles.label}>邮箱</Text>
<TextInput
style={[styles.input, errors.email && styles.inputError]}
value={formData.email}
onChangeText={(text) => handleChange('email', text)}
placeholder="请输入邮箱"
keyboardType="email-address"
autoCapitalize="none"
/>
{errors.email && <Text style={styles.errorText}>{errors.email}</Text>}
</View>
<View style={styles.inputContainer}>
<Text style={styles.label}>手机号</Text>
<TextInput
style={[styles.input, errors.phone && styles.inputError]}
value={formData.phone}
onChangeText={(text) => handleChange('phone', text)}
placeholder="请输入手机号"
keyboardType="phone-pad"
/>
{errors.phone && <Text style={styles.errorText}>{errors.phone}</Text>}
</View>
<View style={styles.inputContainer}>
<Text style={styles.label}>个人简介</Text>
<TextInput
style={[styles.input, styles.textArea]}
value={formData.bio}
onChangeText={(text) => handleChange('bio', text)}
placeholder="请输入个人简介"
multiline
numberOfLines={4}
/>
</View>
<TouchableOpacity
style={[styles.button, isSubmitting && styles.buttonDisabled]}
onPress={handleSubmit}
disabled={isSubmitting}
>
<Text style={styles.buttonText}>
{isSubmitting ? '提交中...' : '保存修改'}
</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
form: {
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
textAlign: 'center',
},
inputContainer: {
marginBottom: 16,
},
label: {
fontSize: 16,
marginBottom: 8,
fontWeight: '500',
},
input: {
backgroundColor: '#fff',
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 8,
padding: 12,
fontSize: 16,
},
textArea: {
height: 100,
textAlignVertical: 'top',
},
inputError: {
borderColor: '#ff3b30',
},
errorText: {
color: '#ff3b30',
fontSize: 12,
marginTop: 4,
},
button: {
backgroundColor: '#007AFF',
borderRadius: 8,
padding: 16,
alignItems: 'center',
marginTop: 20,
},
buttonDisabled: {
backgroundColor: '#ccc',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});
export default ProfileEditScreen;步骤2:更新导航配置
更新 src/navigation/StackNavigators.js 文件,添加个人资料编辑页面:
javascript
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from '../screens/HomeScreen';
import ProfileScreen from '../screens/ProfileScreen';
import ProfileEditScreen from '../screens/ProfileEditScreen';
import CalculatorScreen from '../screens/tools/CalculatorScreen';
import NotesScreen from '../screens/tools/NotesScreen';
import NoteDetailScreen from '../screens/tools/NoteDetailScreen';
const Stack = createStackNavigator();
export const HomeStack = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="HomeMain"
component={HomeScreen}
options={{ title: '首页' }}
/>
</Stack.Navigator>
);
};
export const ProfileStack = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="ProfileMain"
component={ProfileScreen}
options={{ title: '个人中心' }}
/>
<Stack.Screen
name="ProfileEdit"
component={ProfileEditScreen}
options={{ title: '编辑资料' }}
/>
</Stack.Navigator>
);
};
export const ToolsStack = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="ToolsMain"
component={ToolsScreen}
options={{ title: '工具' }}
/>
<Stack.Screen
name="Calculator"
component={CalculatorScreen}
options={{ title: '计算器' }}
/>
<Stack.Screen
name="Notes"
component={NotesScreen}
options={{ title: '便签' }}
/>
<Stack.Screen
name="NoteDetail"
component={NoteDetailScreen}
options={{ title: '便签详情' }}
/>
</Stack.Navigator>
);
};步骤3:更新个人中心页面
更新 src/screens/ProfileScreen.js 文件,添加编辑资料按钮:
javascript
import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Image } from 'react-native';
import { useNavigation } from '@react-navigation/native';
const ProfileScreen = () => {
const navigation = useNavigation();
// 模拟用户数据
const userData = {
name: '张三',
email: 'zhangsan@example.com',
phone: '13800138000',
bio: '这是个人简介',
};
const handleEditProfile = () => {
navigation.navigate('ProfileEdit', { userData });
};
return (
<View style={styles.container}>
<View style={styles.header}>
<Image
source={{ uri: 'https://via.placeholder.com/150' }}
style={styles.avatar}
/>
<Text style={styles.name}>{userData.name}</Text>
<Text style={styles.email}>{userData.email}</Text>
<TouchableOpacity
style={styles.editButton}
onPress={handleEditProfile}
>
<Text style={styles.editButtonText}>编辑资料</Text>
</TouchableOpacity>
</View>
<View style={styles.infoSection}>
<Text style={styles.infoTitle}>个人信息</Text>
<View style={styles.infoItem}>
<Text style={styles.infoLabel}>手机号:</Text>
<Text style={styles.infoValue}>{userData.phone}</Text>
</View>
<View style={styles.infoItem}>
<Text style={styles.infoLabel}>简介:</Text>
<Text style={styles.infoValue}>{userData.bio}</Text>
</View>
</View>
<View style={styles.menuSection}>
<TouchableOpacity style={styles.menuItem}>
<Text style={styles.menuText}>设置</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.menuItem}>
<Text style={styles.menuText}>关于</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.menuItem}>
<Text style={styles.menuText}>退出登录</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
header: {
backgroundColor: '#fff',
padding: 20,
alignItems: 'center',
borderBottomWidth: 1,
borderBottomColor: '#eee',
},
avatar: {
width: 100,
height: 100,
borderRadius: 50,
marginBottom: 16,
},
name: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 8,
},
email: {
fontSize: 14,
color: '#666',
marginBottom: 16,
},
editButton: {
backgroundColor: '#007AFF',
paddingHorizontal: 20,
paddingVertical: 8,
borderRadius: 20,
},
editButtonText: {
color: '#fff',
fontSize: 14,
fontWeight: '500',
},
infoSection: {
backgroundColor: '#fff',
marginTop: 16,
padding: 20,
},
infoTitle: {
fontSize: 16,
fontWeight: '600',
marginBottom: 16,
},
infoItem: {
flexDirection: 'row',
marginBottom: 12,
},
infoLabel: {
fontSize: 14,
color: '#666',
width: 80,
},
infoValue: {
fontSize: 14,
flex: 1,
},
menuSection: {
backgroundColor: '#fff',
marginTop: 16,
},
menuItem: {
padding: 16,
borderBottomWidth: 1,
borderBottomColor: '#eee',
},
menuText: {
fontSize: 16,
},
});
export default ProfileScreen;步骤4:更新工具页面导入
确保 src/navigation/StackNavigators.js 中导入了 ToolsScreen:
javascript
import ToolsScreen from '../screens/ToolsScreen';表单提交功能总结
在本部分中,我们实现了以下功能:
- 个人资料编辑页面:创建了一个包含姓名、邮箱、手机号和个人简介的表单
- 表单验证:实现了基本的表单验证逻辑,包括必填项和格式验证
- 表单提交:模拟了表单提交过程,包括加载状态和错误处理
- 导航集成:将编辑页面集成到导航系统中,支持页面间数据传递
- 用户界面:设计了美观的表单界面,包括输入框、标签和错误提示
下一步
在下一节中,我们将继续完善个人主页/小工具APP,添加原生功能整合,包括相机/相册调用、定位功能等。
